#!/usr/bin/env python import xmllib import sys, os, string, re #============================================================== # get_help_info #============================================================== def get_help_info() : str = "\nPAL/SALOME Installation Wizard\n\n" str = str + "\tUsage : \n\tInstall [-g|b] [-f ] [-t ] [-tmp ]\n" str = str + "\n" str = str + " -g Runs the Installation Wizard in the GUI mode.\n" str = str + " In this case only is taken into account \n" str = str + " from the parameters list. This key is default.\n" str = str + "\n" str = str + " -b Runs the Installation Wizard in the batch mode.\n" str = str + " All the found parameters are taken in to account.\n" str = str + "\n" str = str + " -f The configuration file to be parsed by the Installation Wizard.\n" str = str + " If this parameter is missed then the script tries to define\n" str = str + " the Red Hat version and use the corresponding xml. For example,\n" str = str + " for Red Hat 8.0 config_RedHat8_0.xml file is supposed to be used\n" str = str + " by default. If the appropriate xml file is not found, the config.xml\n" str = str + " is used by default.\n" str = str + "\n" str = str + " -t The target directory the products to be installed to.\n" str = str + " This parameter overloads the target directory described in the\n" str = str + " configuration file.\n" str = str + "\n" str = str + " -tmp The directory which should be used for the temporary files.\n" str = str + " This parameter overloads the temporary directory described in the\n" str = str + " configuration file.\n" str = str + "\n" str = str + " -h Prints help information.\n" return str #============================================================== # error_exit #============================================================== def error_exit (str = ""): import sys if len(str): res = "\n" + str + "\n" else : res = "" print res + \ get_help_info() sys.exit(1); #============================================================== # Cheks whether the passed parameter is a key. #============================================================== def is_key ( val ): import re if val is not None : return re.match(r'^-[a-zA-Z]', val) return 0 #============================================================== # From the list of parameters extracts value following 'key' #============================================================== def extract_parameter ( key, args ) : import sys length = len(args); if ( length == 0 ) : return None found = 0; for i in range(0, length-1): if args[i] == key : if ( is_key ( args[i+1]) ) : print " No value after key ", key sys.exit(1); value = args[i+1] if ( i < length - 2 and is_key ( args[i+2] ) == 0 ) : #control that only one value follows key #(not a list). In this case params are correct. print "Too much values after key ", key sys.exit(1); found = 1; break; if (found) : return value return None #=============================================================== # Extracts list of values following specified 'key' from 'args[]' #=============================================================== def extract_list (key, args) : lenght = len(args) if ( args is None or lenght == 0 ): error_exit() list=[] found = 0 for i in range(0, length) : if args[i] == key : if (is_key ( args[i+1])) : error_exit(); for i in range (i+1, lenght): if is_key(args[i]) : break list.append(args[i]) found =1; break return list; #empty list is returned if no values after key #============================================================== # Method find the $key in the list and return 1 if success # and 0 otherwise. #============================================================== def find_key (key, argv) : if (not is_key(key)) : return 0 for simbol in argv : if simbol == key: return 1 return 0 #============================================================== # Parse the list of parameters #============================================================== def parse_parameters (args) : if find_key('-h', args) : print get_help_info(); import sys sys.exit(0) xmlfile = extract_parameter("-f", args) target_dir = extract_parameter("-t", args) tmp_dir = extract_parameter("-tmp", args) if find_key('-b', args): is_gui = 0 else : is_gui = 1 return [xmlfile, target_dir, tmp_dir, is_gui] #================================================================= # The first algorithm to create the dependencies list by their level #================================================================= def get_next_level(list, products): import re result = [] expr = "(" + list[0].name for i in range(1, len(list)): expr = expr + "|"+ list[i].name expr = expr + ")$" #expr=re.compile(expr) for product in products: deps = re.sub(r'\s+', "", product.dependencies) if re.search(expr, deps): result.append(product) return result def create_levels(prods): import copy products = copy.deepcopy(prods) result = {} import re #1. find the products with empty lists of dependencies list = [] for product in products: if len(re.sub(r'\s', "", product.dependencies)) == 0 : list.append(product) if len(list) == 0 : raise RuntimeError, "Products that depend on nothing are not found" # remove the first level products from the common list of products for product in list : products.remove(product) ind = 0; result[0] = list while (len(products)) : res = get_next_level(list, products) if len(res) == 0 : raise RuntimeError, "Empty list of products is found" for product in res : products.remove(product) ind = ind +1 result[ind] = res list = res str = "" for i in result.keys(): for product in result[i]: str = str + product.name + " " return str; #================================================================= # The second algorithm #================================================================= def get_dependencies_set(prods) : import copy import re products = copy.deepcopy(prods) deps = "" list = [] while (len(products)) : tmplist = [] #find the products with empty list of dependencies for product in products: product.dependencies = re.sub(r'\s+$', "", product.dependencies) product.dependencies = re.sub(r'^\s+', "", product.dependencies) if len(product.dependencies) == 0 : tmplist.append(product); deps = deps + " " + product.name list.append(tmplist) #remove the products names from other products dependencies for item in tmplist: products.remove(item) regexpr1 = "((^|,(\s+)?)"+item.name+"$|^"+item.name+"(\s+)?,(\s+)?)" regexpr2 = ",(\s+)?"+item.name+"(\s+)?,(\s+)?" for product in products: product.dependencies = re.sub(r'\s+$', "", product.dependencies) product.dependencies = re.sub(r'^\s+', "", product.dependencies) product.dependencies = re.sub(regexpr1, "", product.dependencies) product.dependencies = re.sub(regexpr2, ",", product.dependencies) return deps #============================================================== # Creates dir, returns the part of path that existed early. # Access may be defined. #============================================================== def create_dir (directory, access = 0777): import string, os dirs = string.split(directory, "/") existing = ""; dir = "" root = "" for item in dirs: if len(item) == 0: continue dir = dir + "/"+item if os.path.exists(dir): existing = dir else: os.mkdir(dir, access ) #root= existing + "/"+item if dir == existing + "/"+item : root = dir #else : root = existing return root #============================================================== # class Product #============================================================== class Product : def __init__(self, theName, theVersion = None, theInstall = None, theSupportred = None, theDisable = None, theDependencies = None, theInstalldiskspace = None, theTemporarydiskspace = None, theScript = None): self.name = theName self.version = theVersion self.install = theInstall self.supported = theSupportred self.disable = theDisable self.dependencies = theDependencies self.installdiskspace = theInstalldiskspace self.temporarydiskspace = theTemporarydiskspace self.script = theScript #=================================================================== # class Config #=================================================================== class Config : def __init__(self, theVersion='', theCaption='', theCopyright='', theLicense='', theOS=''): self.version = theVersion self.caption = theCaption self.copyright = theCopyright self.license = theLicense self.os = theOS #=================================================================== # class Path #=================================================================== class Path : def __init__(self, theTargetdir=".", theTmpdir="."): self.targetdir = theTargetdir self.tmpdir = theTmpdir #=================================================================== # class ConfigParser #=================================================================== class ConfigParser(xmllib.XMLParser): def __init__(self): xmllib.XMLParser.__init__(self) self.products = [] self.currentdata = [] self.path = None self.config = None def handle_data(self, data): self.currentdata.append(data) def start_product(self, attrs): aProduct = Product(attrs['name'], attrs['version'], attrs['install'], attrs['supported'], attrs['disable'], attrs['dependancies'], attrs['installdiskspace'], attrs['temporarydiskspace'], attrs['script']) self.products.append(aProduct) def end_product(self): pass def start_config(self, attrs): self.config = Config(attrs['version'], attrs['caption'], attrs['copyright'], attrs['license'], attrs['os']) def end_config(self): pass def start_path (self, attrs): self.path = Path(attrs['targetdir'], attrs['tempdir']) print self.path.tmpdir def end_path(self): pass def getProduct(self, prod): for product in self.products: if product.name == prod: return product return None #================================================================ # get the path using file name #================================================================ def get_current_path(file_name): path = "."; where = string.rfind(file_name,'/'); if (where != -1): path = (file_name)[: where] os.chdir(path); path = os.getcwd() + "/" return path #================================================================ # checks dir existing #================================================================ def check_dir(dir): if (os.path.islink(dir)) : native_dir = os.readlink(dir) if not os.path.exists(native_dir) : print "Bad link " + native_dir + " to directory " + native_dir + ". The last does not exist." return 0 # problem else : if not os.path.exists(dir): print "Directory " + dir + " does not exist" return 0 return 1 #=============================================================== # Checks the disk space. Exit from interpreter if there is no # enough disk space. #=============================================================== def check_disk_space(products, script_dir, target_dir, tmp_dir): import re, string, os install_space = 0 temporary_space = 0 for product in products : product.install = re.sub(r'^\s+', "", product.install) product.install = re.sub(r'\s+$', "", product.install) if product.disable == "true" or product.install == "use native": continue spaces = string.split( product.installdiskspace,',') prod_space = spaces[0] if (len(spaces) == 2 ) and (product.install == "install binaries") : prod_space = spaces[1] install_space = install_space + string.atoi(prod_space) temporary_space = temporary_space + string.atoi(product.temporarydiskspace) res = os.system(scripts_dir + "checkSize.sh" + " " + target_dir + " " + str(install_space)) if res: print "There is no enough space to install the products." return 0 res = os.system(scripts_dir + "checkSize.sh" + " " + tmp_dir + " " + str(temporary_space)) if res: print "There is no enough space for tmp directory." return 0 return 1 #================================================================ # main #================================================================ if __name__ == "__main__": cur_dir = get_current_path(sys.argv[0]) [xml_file, target_dir, tmp_dir, is_gui] = parse_parameters(sys.argv) # define xml file ----------------- if (xml_file is None) : xml_file_name = "config.xml" if os.path.exists("/proc/version"): data = open("/proc/version").readline() res = re.search(r'Red\s+Hat\s+\w+(\s+)?(\d[.]\d)', data) if res is not None: num = re.sub("[.]", "_", (res.groups())[1]) filename = "config_RedHat" + num+ ".xml" if (os.path.exists(cur_dir + filename)): xml_file_name = filename xml_file = cur_dir + xml_file_name if xml_file is None or not os.path.exists(xml_file): error_exit("No xml file is found try to run with options -f ") if not os.access(xml_file, os.R_OK): print "There is no acceess to read "+ xml_file sys.exit(1) #---- GUI ---------------- if is_gui : env = os.environ if not env.has_key("PATH") : env["PATH"] = "" if not env.has_key("LD_LIBRARY_PATH") : env["LD_LIBRARY_PATH"]= "" env["LD_LIBRARY_PATH"] = ".:" + env["LD_LIBRARY_PATH"] env["PATH"] = ".:"+ env["PATH"] sys.exit(os.system("cd " + cur_dir + "; ./bin/SALOME_InstallWizard " + xml_file +"&")) #----- TUI --------------------- #print xml_file, target_dir, tmp_dir, is_gui filehandle = open(xml_file) data = filehandle.read() filehandle.close() parser = ConfigParser() parser.feed(data) parser.close() # definitions : # map what_to_do = { "install sources":"install_source", "install binaries":"install_binary", "use native":"try_native"} # define tmp dir ----------- if tmp_dir is None: tmp_dir = parser.path.tmpdir root_path = "" if not os.path.exists(tmp_dir): print "Creating " + tmp_dir; root_path = create_dir(tmp_dir) ; import random tmp_dir = tmp_dir + "/INSTALLWORK" + str(random.randint(10000,100000)) create_dir(tmp_dir,0755) if not os.path.exists(tmp_dir): error_exit("There is no tmp directory " + tmp_dir + ". Use -tmp key to set directory or correct xml file\n\n") if not os.access(tmp_dir, os.W_OK) : str = "We have no write permissions for directory " + tmp_dir + ". Use -tmp key to set directory or correct xml file" error_exit(str) # define target dir -------- if target_dir is None: target_dir = parser.path.targetdir if not os.path.exists(target_dir): print "Creating " + target_dir; create_dir(target_dir, 0755) if not os.path.exists(target_dir): error_exit("There is no target directory " + target_dir + ". Use -t key to set directory or correct xml file\n\n") if not os.access(target_dir, os.W_OK) : str = "We have no write permissions for directory " + target_dir + ". Use -t key to set directory or correct xml file" error_exit(str) # define products dir ------------ source_dir = cur_dir + "Products" ; if not check_dir(source_dir): if len(root_path) and os.path.exists(root_path): os.system("rm -r -f "+ root_path) sys.exit(1) subdir = {"install sources" : "SOURCES", "install binaries" : "BINARIES/"+parser.config.os, "use native": ""} # define scripts dir ------------ scripts_dir = cur_dir + "config_files/" if not check_dir(scripts_dir): if len(root_path) and os.path.exists(root_path): os.system("rm -r -f "+ root_path) sys.exit(1) os.chdir(scripts_dir) list_of_dep = create_levels(parser.products) #list_of_dep = get_dependencies_set(parser.products) if check_disk_space(parser.products, scripts_dir, target_dir, tmp_dir) : for product in parser.products : if product.disable == "true": continue cmd = scripts_dir + product.script + " " + \ what_to_do[product.install]+ " " + \ tmp_dir + " " + \ source_dir + "/" + subdir[product.install] + " " + \ target_dir + " " + \ '"' + list_of_dep + '"' + " " + \ product.name res = os.system(cmd) if res : break; shFile = target_dir + "/env_products.sh" cshFile = target_dir + "/env_products.csh" binProduct = parser.getProduct("KERNEL-Bin") srcProduct = parser.getProduct("KERNEL-Src") if binProduct: if os.path.exists(shFile): os.system( "cp " + shFile + " " + target_dir + "/KERNEL_" + binProduct.version + "/salome.sh" ) if os.path.exists(cshFile): os.system( "cp " + cshFile + " " + target_dir + "/KERNEL_" + binProduct.version + "/salome.csh" ) if srcProduct: if os.path.exists(shFile): os.system( "cp " + shFile + " " + target_dir + "/KERNEL_SRC_" + binProduct.version + "/salome.sh" ) if os.path.exists(cshFile): os.system( "cp " + cshFile + " " + target_dir + "/KERNEL_SRC_" + binProduct.version + "/salome.csh" ) if len(root_path) and os.path.exists(root_path): os.system("rm -r -f "+ root_path)