#!/usr/bin/env python3 # # This scripts downloads, unpacks and installs the packages required by the # InSAR Scientific Computing Environment (ISCE). It is called by the bash script # install.sh and requires the script setup_config.py. # # Authors : Eric Gurrola, Kosal Khun, Marco Lavalle # Date : April 2013 # Version : 2.0 from __future__ import print_function import sys import os import urllib import getopt import re import shutil import subprocess import datetime import time import platform import traceback import barthread VARENV = ['PATH', 'PYTHONPATH', 'LD_LIBRARY_PATH', 'SCONS_CONFIG_DIR', 'ISCE_HOME'] #environment variables THIS_FOLDER = os.path.dirname(os.path.abspath(__file__)) #folder containing this file CONFIG_FOLDER = os.path.join(os.path.dirname(THIS_FOLDER), 'configuration') #name of configuration folder in the ISCE source tree SCONS_CONFIG_DIR = os.path.join(os.getenv('HOME'), '.isce') #folder where config file will be written CONFIG_FILE = 'SConfigISCE' #name of config file to be created BASH_FILE = os.path.join(SCONS_CONFIG_DIR, '.isceenv') #source this file in order to define environment variables SETUP_CONFIG = 'setup_config' #name of file (without .py) inside THIS_FOLDER, with dependencies to be downloaded CONTACT = "isceteam@gmail.com" #email address shown when an error happens SETUP_LOG = os.path.join(SCONS_CONFIG_DIR, 'setup.log') #log file for the installation (inside the SCONS_CONFIG_DIR) LOGFILE = None #the log file object referring to SETUP_LOG VERBOSE = False #default verbose value WORKING = None #barthread display def usage(): """ Print a message about how to use install.sh """ print("%s must be called by install.sh\n" % os.path.basename(__file__)) subprocess.check_call(os.path.join(THIS_FOLDER, "install.sh -h"), shell=True) def print2log(msg, withtime=True, cmd=False): """ Output the message displayed by the setup script to LOGFILE and to the standard output """ global LOGFILE print(msg) if cmd: msg = "Issuing command:\n\t%s" % msg if withtime: now = datetime.datetime.today() msg = "%s >> %s" % (now.isoformat(), msg) LOGFILE.write((msg + '\n').encode('utf-8')) LOGFILE.flush() os.fsync(LOGFILE) def executeCommand(command, logfile, critical=True, executable='bash'): """ Take a command and add extra code so that messages are logged to a file (logfile) and displayed on standard output. The exit status of the command (and not the exit status of tee) is returned to subprocess. If critical, the program exits. executable is the shell to use. """ global WORKING if logfile is not None: print2log("Output messages of this command can be found in file %s" % logfile) if VERBOSE: if logfile is None: loggedcommand = command else: loggedcommand = "%s 2>&1 | tee -a %s; exit ${PIPESTATUS[0]}" % (command, logfile) else: if logfile is None: loggedcommand = "%s > /dev/null" % command else: loggedcommand = "%s >> %s 2>&1" % (command, logfile) WORKING = barthread.BarThread() try: subprocess.check_call(loggedcommand, shell=True, executable=executable) if WORKING: WORKING.stop() WORKING = None else: print2log("Done") except subprocess.CalledProcessError as e: if WORKING: WORKING.stop(False) WORKING = None print2log("...An error occurred with exit status %s. You can find more details in the file %s" % (e.returncode, logfile)) if critical: sys.exit(1) else: print2log("...Non critical error, command skipped.") def printenv(msg): msg = "************\n" + msg for var in VARENV: try: env = os.environ[var] except KeyError: env = "" msg += "%s=%s\n" % (var, env) msg += "************" print2log(msg) def changedir(folder): print2log("cd %s" % folder, cmd=True) os.chdir(folder) def createfolder(folder): print2log("mkdir -p %s" % folder, cmd=True) os.makedirs(folder) def removefolder(folder): """ Remove a folder using shutil.rmtree If fails, use removeall() """ if os.path.exists(folder): print2log("rm -rf %s" % folder, cmd=True) try: shutil.rmtree(folder) except OSError: removeall(folder) def removeall(folder): """ Remove a folder recursively using os.remove """ if not os.path.isdir(folder): return files = os.listdir(folder) for f in files: fullpath = os.join(folder, f) if os.path.isfile(fullpath): os.remove(fullpath) elif os.path.isdir(fullpath): removeall(fullpath) os.rmdir(fullpath) def downloadfile(url, fname, repeat=1): counter = 0 while counter < repeat: try: response = urllib.request.urlopen(url) break except urllib.request.URLError as e: counter += 1 if hasattr(e, 'reason'): print2log("Failed to reach server. Reason: %s" % e.reason) if counter == repeat: return False time.sleep(1) #wait 1 second elif hasattr(e, 'code'): print2log("The server couldn't fulfill the request. Error code: %s" % e.code) return False data = response.read() with open(fname, 'wb') as code: code.write(data) return True class InstallItem(object): """ This class allows unpacking and installation of a package. """ def __init__(self, item, paths): self.item = item self.paths = paths self.flags = None; self.getFlags() self.this_src = None self.this_bld = None def getFlags(self): """ Get the flags used to install the item. """ user_flags = self.item.properties['user_flags'] flags_list = self.item.properties['flags_list'] SPC = " " if user_flags: if type(user_flags) in (list, tuple): FL = user_flags elif type(flags) is str: FL = user_flags.split() else: print2log("ProgError: user_flags for %s must be a list or a string" % self.item.name) sys.exit(1) elif flags_list: if type(flags_list) in (list, tuple): FL = [SPC, "--prefix=" + self.paths.prefix] FL.extend(flags_list) else: print2log("ProgError: flags_list for %s must be a list" % self.item.name) sys.exit(1) else: FL = [SPC, "--prefix=" + self.paths.prefix] self.flags = SPC.join(FL) def unpack(self, toUnpack=True): """ Get the folder where the package will be untarred Unpack the item if toUnpack=True """ global WORKING destfile = self.item.destfile destfolder, fname = os.path.split(destfile) ns = fname.split('.') if ('tar' in ns) or ('tgz' in ns) and (ns.index('tgz') == len(ns)-1): if ns[-1] == 'tar': flag = "xvf" self.this_src = destfile[:-4] elif ns[-1] in ['tgz']: flag = "xzvf" self.this_src = destfile[:-4] elif ns[-1] in ['gz']: flag = "xzvf" self.this_src = destfile[:-7] elif ns[-1] in ['bz2']: flag = "xjvf" self.this_src = destfile[:-8] else: print2log("Unknown tar file type: %s" % fname) sys.exit(1) if toUnpack: print2log("Unpacking %s ..." % fname) if not os.path.isfile(destfile): print2log("Could not find file %s. Please download it first using -d %s" % (destfile, self.item.name)) sys.exit(1) changedir(self.paths.src) command = "tar -%s %s" % (flag, destfile) print2log(command, cmd=True) if not VERBOSE: command += " > /dev/null" WORKING = barthread.BarThread() subprocess.check_call(command, shell=True) WORKING.stop() WORKING = None else: print2log("...unsupported archive scheme for %s" % destfile) sys.exit(1) def install(self): """ Install the item. Method can be config (make) or setup (setup.py) """ env = self.item.properties['environment'] method = self.item.properties['installation_method'] if env: self.setEnv(env) cwd = self.cd_this_bld() build_folder = os.path.basename(self.this_bld) print2log("Installing %s ..." % build_folder) if not os.path.isdir(self.this_src): print2log("Could not find folder %s. Please download and unpack %s first." % (self.this_src, self.item.name)) sys.exit(1) if method == 'config': builddir = self.this_bld if self.item.properties['prestring']: prestr = self.item.properties['prestring'] + " " else: prestr = "" if platform.system().lower() == "freebsd": make = "gmake" #for FreeBSD, use gmake instead of make else: make = "make" commands = [("configure", prestr + os.path.join(self.this_src, "configure") + self.flags, True), ("build", make, True), ("install", make + " install", True)] elif method == 'setup': #we build in src folder rather than in build folder (some setup.py won't work otherwise) builddir = self.this_src if "--prefix=" in self.flags: #replace --prefix=path by --home=path (the python module will be installed in path/lib(64)/python/) self.flags = self.flags.replace("--prefix=", "--home=") #execute: setup.py configure with flags commands = [("setup", "python " + os.path.join(self.this_src, "setup.py configure " + self.flags), False)] #previous command gives an error if configure is not needed, the script will then skip "configure" #execute setup.py install commands.append(("setup", "python " + os.path.join(self.this_src, "setup.py install " + self.flags), True)) else: print2log("ProgError: Unknown installation method for %s." % self.item.name) sys.exit(1) changedir(builddir) printenv("Current values of environment variables:\n") for (step, command, critical) in commands: print2log(command, cmd=True) logfile = "%s_%s.log" % (os.path.join(self.this_bld, self.item.name), step) executeCommand(command, logfile, critical) changedir(cwd) if env: self.restoreEnv() print2log("Installation of %s done" % self.item.name) def cd_this_bld(self): """ Return the current directory and create build directory """ cwd = os.getenv('PWD') self.this_bld = os.path.join(self.paths.bld, os.path.basename(self.this_src)) removefolder(self.this_bld) createfolder(self.this_bld) return cwd def setEnv(self, vars_dict): """ Save current environment and update environment with variables in vars_dict """ self.env = {} for var, val in vars_dict.items(): self.env[var] = os.getenv(var) os.environ[var] = val def restoreEnv(self): """ Restore environment saved by setEnv """ for var, val in self.env.items(): if val: os.environ[var] = val else: os.environ.pop(var) class Paths(object): """ This class allows the creation of subdirectories below prefix """ def __init__(self, prefix, python_version): self.prefix = prefix paths = [] for folder in ["src", "bin", "lib", "include", "build"]: path = os.path.join(prefix, folder) if not os.path.isdir(path): createfolder(path) paths.append(path) (self.src, self.bin, self.lib, self.inc, self.bld) = tuple(paths) pkg_dir = ':'.join( [ os.path.join(self.lib + bits, "python") for bits in ['64', '', '32'] ] ) self.pkg = pkg_dir class URLItem(object): """ This class defines an item (i.e., a dependency) with its url and properties """ def __init__(self, name, urls, properties): self.name = name self.urls = urls keys = ('installation_method', 'flags_list', 'user_flags', 'prestring', 'environment') if len(keys) != len(properties): print2log("ProgError: Please check that the properties given are correct for %s in class ISCEDeps." % name) sys.exit(1) self.properties = dict(zip(keys, properties)) class ISCEDeps(object): """ This class prepares the environment and installs dependencies, before installing ISCE. """ dependency_list = ["GMP", "MPFR", "MPC", "GCC", "SCONS", "FFTW", "SZIP", "HDF5", "NUMPY", "H5PY"] #list of packages that can be installed, order matters! use uppercase! deplog_key = ["skipped", "downloaded", "unpacked", "installed"] #dependency log def __init__(self, **kwargs): global VERBOSE try: VERBOSE = kwargs["verbose"] except: pass version = sys.version_info self.python_version = "{}.{}".format(version.major, version.minor) # p = subprocess.Popen(['python3', '-V'], stdout=subprocess.PIPE) # x = p.communicate()[0] # stv = ''.join([e if isinstance(e,str) else e.decode("utf-8") for e in x]) # self.python_version = "%s.%s" % tuple(stv.split(' ')[1].split('.')[:2]) # python_version is now the python3 version (not the sys.version_info) self.uname = kwargs["uname"] self.bash_vars = [] #environment variables to be written in bash file self.dependency_log = {} for key in self.deplog_key: self.dependency_log[key] = [] self.prefix = kwargs["prefix"] if self.prefix: #if prefix given self.paths = Paths(self.prefix, self.python_version) else: self.paths = None try: #config file is given: skip installation of dependencies self.config = kwargs["config"] return except KeyError: #config file not given self.config = None #read setup_config.py setup_config = readSetupConfig(SETUP_CONFIG + '.py') properties = {} # dictionary of properties for each item to be installed GCC = kwargs["gcc"] GXX = kwargs["gpp"] prestring = "CC=" + GCC + " CXX=" + GXX env = { #use the latest compilers installed with gcc 'CC': os.path.join(self.paths.bin, "gcc"), 'F77': os.path.join(self.paths.bin, "gfortran") } #to add a new item: #properties[name_of_item] = (installation_method, flags_list, user_flags, prestring, environment) properties["GMP"] = ("config", ["--enable-cxx"], None, prestring, None) properties["MPFR"] = ("config", ["--with-gmp=" + self.prefix], None, prestring, None) properties["MPC"] = ("config", ["--with-gmp=" + self.prefix, "--with-mpfr=" + self.prefix], None, None, None) properties["GCC"] = ("config", ["--with-gmp=" + self.prefix, "--with-mpfr=" + self.prefix, "--enable-languages=c,c++,fortran", "--enable-threads"], None, prestring, None) properties["SCONS"] = ("setup", [], None, None, None) properties["FFTW"] = ("config", ["--enable-single", "--enable-shared"], None, None, env) properties["SZIP"] = ("config", [], None, None, None) properties["HDF5"] = ("config", ["--enable-fortran", "--enable-cxx"], None, None, None) properties["NUMPY"] = ("setup", [], None, None, None) properties["H5PY"] = ("setup", ["--hdf5=" + self.prefix], None, None, None) """ TODO: we can try to support the installation of the following packages if needed properties["MOTIF"] = ("config", [], None, None, None) properties["SPHINX"] = ("setup", [], None, None, None) properties["XT"] = ("config", [], None, None, None) properties["XP"] = ("config", [], None, None, None) """ self.urlitems = {} #install dependencies for dep in self.dependency_list: self.make_urls(setup_config, dep, properties[dep]) toDownload = kwargs["download"] toUnpack = kwargs["unpack"] toInstall = kwargs["install"] if not (toDownload + toUnpack + toInstall): # none given: do everything toDownload = self.dependency_list toUnpack = self.dependency_list toInstall = self.dependency_list else: # at least one is given toDownload = self.getDepList(toDownload) # get list of dependencies to download toUnpack = self.getDepList(toUnpack) # get list of dependencies to unpack toUnpack.extend(toDownload) # add depedencies from download list toUnpack = ",".join(toUnpack) # make list back into a comma-separated string toUnpack = self.getDepList(toUnpack) # remove duplicata and reorder dependencies toInstall = self.getDepList(toInstall) # get list of dependencies to install toInstall.extend(toUnpack) # add dependencies from unpack list (and download list) toInstall = ",".join(toInstall) # make list into a comma-separated string toInstall = self.getDepList(toInstall) # remove duplicata and reorder dependencies self.toDownload = toDownload self.toUnpack = toUnpack self.toInstall = toInstall def getDepList(self, depList): """ Take a string and return a list of dependencies The list is ordered according to self.dependency_list """ if depList.upper() == "NONE" or depList == "": return [] elif depList.upper() == "ALL": return list(self.dependency_list) else: fill = False if depList.endswith('+'): #given string ends with > fill = True depList = depList[:-1] givenList = depList.upper().split(",") if fill: #get last element of given list last = givenList[-1] #find where last element is located in dependency_list index = self.dependency_list.index(givenList[-1]) #append all dependencies following last element givenList.extend(self.dependency_list[index+1:]) depList = [] for dep in self.dependency_list: if dep in givenList and dep in self.urlitems: depList.append(dep) return depList def make_urls(self, config, dependency, properties): """ Check if a dependency is in config file And add corresponding URLItem object to self.urlitems """ try: urls = config[dependency] item = URLItem(dependency, urls, properties) urlpath, fname = os.path.split(urls[0]) item.destfile = os.path.join(self.paths.src, fname) self.urlitems[dependency] = item except AttributeError: self.dependency_log["skipped"].append(dependency) print2log("Item %s not given in %s.py. Proceeding as if it has already been installed and hoping for the best..." % (dependency, SETUP_CONFIG)) def run(self): """ Run main script for installing dependencies and ISCE """ self.prepare() #prepare environment for installation self.installIsce() #install isce with Scons self.createBashFile() #create a bash file with environment variables def unpackinstall(self): """ Unpack the dependencies in self.toUnpack (if needed) then install those in self.toInstall """ insList = [] for dep in self.toInstall: item = self.urlitems[dep] ins = InstallItem(item, self.paths) if dep in self.toUnpack: ins.unpack(True) self.dependency_log["unpacked"].append(ins.item.name) else: ins.unpack(False) insList.append(ins) for ins in insList: ins.install() self.dependency_log["installed"].append(ins.item.name) def download(self): """ Download the dependencies specified in self.toDownload """ global WORKING for dep in self.toDownload: item = self.urlitems[dep] for url in item.urls: urlpath, fname = os.path.split(url) print2log("Downloading %s from %s to %s" % (fname, urlpath, self.paths.src)) WORKING = barthread.BarThread() response = downloadfile(url, item.destfile, repeat=2) if response: if os.path.exists(item.destfile): self.dependency_log["downloaded"].append(item.name) WORKING.stop() WORKING = None break else: continue if not os.path.exists(item.destfile): msg = "Cannot download %s. Please check your internet connection and make sure that the download url for %s in %s.py is correct.\n" msg += "You might also consider installing the package manually: see tutorial." % (fname, item.name, SETUP_CONFIG) print2log(msg) sys.exit(1) def createConfigFile(self): """ Create SConfigISCE file """ MANDATORY_VARS = ['PRJ_SCONS_BUILD', 'PRJ_SCONS_INSTALL', 'LIBPATH', 'CPPPATH', 'FORTRAN', 'CC', 'CXX', 'FORTRANPATH'] # ML added FORTRANPATH 2014-04-02 OPTIONAL_VARS = ['MOTIFLIBPATH', 'X11LIBPATH', 'MOTIFINCPATH', 'X11INCPATH'] mandatory_ok = True optional_ok = True msg = "Creating configuration file...\n" self.config_values['PRJ_SCONS_BUILD'] = os.path.join(self.paths.bld, 'isce_build') msg += "ISCE will be built in %s\n" % self.config_values['PRJ_SCONS_BUILD'] self.config_values['PRJ_SCONS_INSTALL'] = os.getenv('ISCE_HOME') msg += "ISCE will be installed in %s\n" % self.config_values['PRJ_SCONS_INSTALL'] libpath = [] for bits in ["64", "", "32"]: if os.path.isdir(self.paths.lib + bits): libpath.append(self.paths.lib + bits) self.updatePath('LD_LIBRARY_PATH', libpath) libpath = os.getenv('LD_LIBRARY_PATH').split(':') self.config_values['LIBPATH'] = " ".join(libpath) msg += "Libraries will be checked inside %s\n" % self.config_values['LIBPATH'] print(os.path.join('python' + self.python_version + 'm', 'Python.h')) CPPPATH = self.getFilePath(os.path.join('python' + self.python_version + 'm', 'Python.h')) # ML added +'m' on 2014-04-02 to reflect new location self.config_values['CPPPATH'] = os.path.join(CPPPATH, 'python' + self.python_version + 'm') # ML added +'m' on 2014-04-02 to reflect new location print(os.path.join(CPPPATH, 'python' + self.python_version + 'm')) if CPPPATH: msg += "Python.h was found in %s\n" % self.config_values['CPPPATH'] else: mandatory_ok = False msg += "Python.h could NOT be found. Please edit the file %s and add the location of Python.h for the variable CPPPATH\n" % CONFIG_FILE fortranpath = self.getFilePath('fftw3.f') self.config_values['FORTRANPATH'] = fortranpath if fortranpath: msg += "fftw3.f was found in %s\n" % self.config_values['FORTRANPATH'] else: mandatory_ok = False msg += "fftw3.f could NOT be found. Please edit the file %s and add the location of fftw3.f for the variable FORTRANPATH\n" % CONFIG_FILE COMPILERS = [ ('Fortran', 'FORTRAN', 'gfortran'), #(compiler name, variable name, executable name) ('C', 'CC', 'gcc'), ('C++', 'CXX', 'g++') ] for compiler in COMPILERS: path = self.getFilePath(compiler[2]) self.config_values[compiler[1]] = os.path.join(path, compiler[2]) if path: msg += "The path of your %s compiler is %s\n" % (compiler[0], self.config_values[compiler[1]]) else: mandatory_ok = False msg += "No %s compiler has been found. Please edit the file %s and add the location of your %s compiler for the variable %s\n" % (compiler[0], CONFIG_FILE, compiler[0], compiler[1]) if self.uname == 'Darwin': #Mac OS ext = 'dylib' else: #should be Linux (doesn't work with Windows) ext = 'so' MDX_DEP = [ ('MOTIFLIBPATH', 'libXm.' + ext), #(variable name, library name) ('X11LIBPATH', 'libXt.' + ext), ('MOTIFINCPATH', os.path.join('Xm', 'Xm.h')), ('X11INCPATH', os.path.join('X11', 'X.h')) ] for dep in MDX_DEP: path = self.getFilePath(dep[1]) self.config_values[dep[0]] = path if path: msg += "The path of %s is %s\n" % (dep[1], path) else: optional_ok = False msg += "%s has NOT been found. Please edit the file %s and add the location of %s for the variable %s\n" % (dep[1], CONFIG_FILE, dep[1], dep[0]) config_vars = MANDATORY_VARS if optional_ok: config_vars.extend(OPTIONAL_VARS) else: print2log("Could not find libraries for building mdx.") f = open(os.path.join(SCONS_CONFIG_DIR, CONFIG_FILE), 'wb') for var in config_vars: f.write("%s=%s\n" % (var, self.config_values[var])) f.close() print2log(msg) if not mandatory_ok: #config file is not complete... msg = "You need to edit the file %s located in %s, before going further.\n" % (CONFIG_FILE, SCONS_CONFIG_DIR) msg += "Then run the following command to install ISCE:\n" msg += "./install.sh -p %s -c %s" % (self.prefix, os.path.join(SCONS_CONFIG_DIR, CONFIG_FILE)) print2log(msg, False) sys.exit(1) def getFilePath(self, name): """ Return a path containing the file 'name'. The path is searched inside env var PATH. """ path_found = "" for path in os.getenv('PATH').split(':'): if path_found: break if os.path.isfile(os.path.join(path, name)): #name found inside path path_found = path else: dirname, basename = os.path.split(path) if basename == 'bin': #if path ends with 'bin' for folder in ['lib64', 'lib', 'lib32', 'include']: #look inside lib and include folders if os.path.isfile(os.path.join(dirname, folder, name)): path_found = os.path.join(dirname, folder) break return path_found def installIsce(self): """ Install ISCE """ print2log("Installing ISCE...") os.environ['PYTHONPATH'] += ":" + CONFIG_FOLDER #add config folder to pythonpath if self.paths: self.updatePath('PATH', [self.paths.bin]) changedir(os.path.dirname(THIS_FOLDER)) command = "scons install" printenv("Current values of environnement variables:\n") logfile = "%s.log" % self.config_values['PRJ_SCONS_BUILD'] print2log(command, cmd=True) executeCommand(command, logfile) def createBashFile(self): """ Create file with environment variables """ f = open(BASH_FILE, 'wb') for var in self.bash_vars: goodpaths = [] exp, val = var.split('=') paths = val.split(':') for path in paths: if os.path.isdir(path): goodpaths.append(path) f.write("%s=%s\n" % (exp, ':'.join(goodpaths))) f.close() msg = "ISCE INSTALLATION DONE\n" msg += "ISCE has been successfully installed!\n" msg += "ISCE applications are located in %s\n" % self.config_values['PRJ_SCONS_INSTALL'] msg += "Environment variables needed by ISCE are defined in the file %s\n" % BASH_FILE msg += "Before running ISCE, source this file in order to add the variables to your environment:\n" msg += " source %s\n" % BASH_FILE msg += "You can source the file in your .bashrc file so that the variables are automatically defined in your shell." print2log(msg) def prepare(self): """ Prepare environment for installation """ self.config_values = {} #variable values to be written to config file (or extracted from config file if given) if self.config: #config file is given by user (packages are supposed to be pre-installed) self.readConfigFile() #read file and update self.config_values self.setEnvironment() else: #config file not given self.setEnvironment() self.download() #download packages... self.unpackinstall() #...and install them self.createConfigFile() #create the config file for Scons for var in ['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'ISCE_HOME']: self.bash_vars.append("export %s=%s" % (var, os.getenv(var))) def updatePath(self, varname, pathlist): """ Append all paths in pathlist at the beginning of env variable varname. """ if type(pathlist) is list: oldpath = os.getenv(varname) if oldpath: #env not empty oldpath = oldpath.split(':') for path in oldpath: if path not in pathlist: #path not in pathlist pathlist.append(path) #add it at the end of pathlist pathlist = ':'.join(pathlist) os.environ[varname] = pathlist def setEnvironment(self): """ Set environment variables """ #Initial values of environment variables printenv("Preparing environment\nInitial values of environment variables:\n") pythonpath = [] if self.config: try: key = 'PRJ_SCONS_INSTALL' isce_home = self.config_values[key] key = 'LIBPATH' lib_path = self.config_values[key].split() except KeyError: print2log("Make sure that %s is present in %s" % (key, self.config)) sys.exit(1) config_dir, config_file = os.path.split(self.config) if config_file != CONFIG_FILE: #make a copy of config file if it's not located in SCONS_CONFIG_DIR config_copy = os.path.join(SCONS_CONFIG_DIR, CONFIG_FILE) shutil.copy(self.config, config_copy) if os.path.isfile(config_copy): #check that file has been copied self.config = config_copy print2log("The config file has been moved to %s" % self.config) config_dir = SCONS_CONFIG_DIR else: msg = "Could not copy %s to %s\n" % (self.config, config_copy) msg += "Please do it manually, then run this command from the setup directory:\n" msg += "./install.sh -c %s" % self.config print2log(msg) sys.exit(1) else: #config file not given isce_home = os.path.join(self.prefix, 'isce') config_dir = SCONS_CONFIG_DIR lib_path = [] for bits in ["64", "", "32"]: lib_path.append(self.paths.lib + bits) if self.paths: pythonpath.append(self.paths.pkg) pythonpath.extend([isce_home, os.path.join(isce_home, 'applications'), os.path.join(isce_home, 'components'), self.prefix]) # added prefix folder to PYTHONPATH 2/12/13 VAR_TO_UPDATE = { 'PYTHONPATH': pythonpath, 'LD_LIBRARY_PATH': lib_path, 'SCONS_CONFIG_DIR': config_dir, 'ISCE_HOME': isce_home, } if self.paths: VAR_TO_UPDATE['PATH'] = [self.paths.bin] if not self.config: # when installing and using gcc, there's a multiarch problem debuting with Ubuntu Natty and Debian Wheezy # we need to give explicitly the search path # http://wiki.debian.org/Multiarch/ if platform.system().lower() == "linux": #distname, version, distid = platform.linux_distribution() #if (distname.lower() == "ubuntu" and version >= "11") or (distname.lower() == "debian" and version >= "7" ): machine = platform.machine() if os.path.isdir("/usr/lib/%s-linux-gnu/" % machine): VAR_TO_UPDATE['LIBRARY_PATH'] = ["/usr/lib/%s-linux-gnu/" % machine] #precompilation search path for libraries VAR_TO_UPDATE['LD_LIBRARY_PATH'].extend(VAR_TO_UPDATE['LIBRARY_PATH']) if os.path.isdir("/usr/include/%s-linux-gnu/" % machine): VAR_TO_UPDATE['CPATH'] = ["/usr/include/%s-linux-gnu" % machine] #precompilation search path for include files for var, pathlist in VAR_TO_UPDATE.items(): self.updatePath(var, pathlist) os.environ['PATH'] += ":%s" % os.path.join(os.getenv('ISCE_HOME'), 'applications') #add applications folder to the path printenv("New values of environment variables:\n") def readConfigFile(self): """ Read config file passed with option -c """ f = open(self.config, 'rb') lines = f.readlines() for line in lines: m = re.match("([^#].*?)=([^#]+?)$", line.strip().decode('utf-8')) if m: var = m.group(1).strip() val = m.group(2).strip() self.config_values[var] = val f.close() def readSetupConfig(setup_config): """ Read setup_config file where urls are given """ params = {} f = open(setup_config, 'rb') lines = f.readlines() for line in lines: m = re.match("([^#].*?)=([^#]+?)$", line.strip().decode('utf-8')) if m: var = m.group(1).strip() val = m.group(2).strip().replace('"', '') if var in params.keys(): params[var].append(val) else: params[var] = [val] f.close() return params def checkArgs(args): """ Check arguments passed to this python file """ try: opts, args = getopt.getopt(args, "h", ["help", "prefix=", "ping=", "config=", "uname=", "download=", "unpack=", "install=", "gcc=", "gpp=", "verbose"]) except getopt.GetoptError as err: print2log("ProgError: %s" % str(err)) usage() sys.exit(2) ok = True ping = "" verbose = False kwargs = {} for o, a in opts: if o in ("-h", "--help"): ok = False break elif o == "--ping": ping = a elif o == "--verbose": kwargs[o[2:]] = True elif o in ["--prefix", "--config", "--uname", "--download", "--unpack", "--install", "--gcc", "--gpp"]: kwargs[o[2:]] = a else: print2log("ProgError: unhandled option: %s" % o) ok = False break if not (ok and ping == "pong"): usage() sys.exit(2) try: kwargs["--prefix"] = os.path.abspath(kwargs["--prefix"]) except KeyError: pass try: kwargs["--config"] = os.path.abspath(kwargs["--config"]) except KeyError: pass return kwargs if __name__ == "__main__": step = 0 witherror = True try: if not os.path.isdir(SCONS_CONFIG_DIR): createfolder(SCONS_CONFIG_DIR) LOGFILE = open(SETUP_LOG, 'ab') #open SETUP_LOG for appending print2log("=" * 60, False) msg = "Starting setup script:\n" msg += " ".join(sys.argv) + "\n" msg += "-" * 60 print2log(msg) step = 1 #get arguments from command line kwargs = checkArgs(sys.argv[1:]) print2log("Checking command line... done") step = 2 a = ISCEDeps(**kwargs) print2log("Initializing script... done") step = 3 print2log("Starting installation...") a.run() witherror = False except KeyboardInterrupt: print2log("Program interrupted by user.") except Exception: if step == 0: msg = "Error when reading script" elif step == 1: msg = "Error when checking command line:" elif step == 2: msg = "Error when initializing script:" elif step == 3: msg = "The script has ended unexpectedly.\n" msg += "##### DEPENDENCIES #####\n" for key in a.deplog_key: try: msg += "%s: %s\n" % (key, ", ".join(a.dependency_log[key])) except KeyError: msg += "%s: none\n" % key msg += "If you run this installation again, you might want to use advanced options for the script. See tutorial.\n\n" print2log("%s\n%s" % (msg, traceback.format_exc())) finally: if WORKING: WORKING.stop(False) WORKING = None print("-" * 60) print("All the displayed messages have been logged to the file %s." % SETUP_LOG) print("-" * 60) msg = "For any questions, contact %s\n" % CONTACT if witherror: msg += "The setup script ended with errors." else: msg += "ISCE seems to have been installed correctly." print2log(msg) LOGFILE.close()