]> SALOME platform Git repositories - tools/install.git/blob - runInstall
Salome HOME
Minor changes
[tools/install.git] / runInstall
1 #!/usr/bin/env python
2
3 import xmllib
4 import sys, os, string, re
5
6 #==============================================================
7 # get_help_info
8 #==============================================================
9 def get_help_info() :
10     str = "\nPAL/SALOME Installation Wizard\n\n"
11     str = str + "\tUsage : \n\tInstall [-g|b] [-f <xml-file>] [-t <target-dir>] [-tmp <tmp-dir>]\n"
12     str = str + "\n"
13     str = str + " -g              Runs the Installation Wizard in the GUI mode.\n"
14     str = str + "                 In this case only <xmlfile> is taken into account \n"
15     str = str + "                 from the parameters list. This key is default.\n"
16     str = str + "\n"
17     str = str + " -b              Runs the Installation Wizard in the batch mode.\n"
18     str = str + "                 All the found parameters are taken in to account.\n"
19     str = str + "\n"
20     str = str + " -f <xml-file>   The configuration file to be parsed by the Installation Wizard.\n" 
21     str = str + "                 If this parameter is missed then the script tries to define\n"
22     str = str + "                 the Red Hat version and use the corresponding xml. For example,\n"
23     str = str + "                 for Red Hat 8.0 config_RedHat8_0.xml file is supposed to be used\n"
24     str = str + "                 by default. If the appropriate xml file is not found, the config.xml\n"
25     str = str + "                 is used by default.\n"
26     str = str + "\n"
27     str = str + " -t <target-dir> The target directory the products to be installed to.\n"
28     str = str + "                 This parameter overloads the target directory described in the\n"
29     str = str + "                 configuration file.\n"
30     str = str + "\n"
31     str = str + " -tmp <tmp-dir>  The directory which should be used for the temporary files.\n"
32     str = str + "                 This parameter overloads the temporary directory described in the\n"
33     str = str + "                 configuration file.\n"
34     str = str + "\n"
35     str = str + " -h              Prints help information.\n" 
36     return str
37
38 #==============================================================
39 # error_exit
40 #==============================================================
41 def error_exit (str = ""):
42     import sys
43     if len(str): res = "\n" + str + "\n"
44     else : res = ""
45     print res + \
46           get_help_info() 
47     sys.exit(1);
48
49
50 #==============================================================
51 # Cheks whether the passed parameter is a key.
52 #==============================================================
53 def is_key ( val ):
54     import re
55     if val is not None : 
56         return re.match(r'^-[a-zA-Z]', val)
57     return 0
58
59 #==============================================================
60 # From the list of parameters extracts value following 'key' 
61 #==============================================================
62 def extract_parameter ( key, args ) :
63     import sys
64     length = len(args);
65     if ( length == 0 ) :  return None
66    
67     found = 0;
68
69     for i in range(0, length-1):
70         if  args[i] == key : 
71             if ( is_key ( args[i+1]) ) :
72                 print " No value after key ", key
73                 sys.exit(1);
74             
75             value = args[i+1]
76             if ( i < length - 2  and is_key ( args[i+2] ) == 0 ) : #control that only one value follows key 
77                                                               #(not a list). In this case params are correct.
78                 print "Too much values after key ", key
79                 sys.exit(1);
80             
81             found = 1; break;
82     
83     if (found) : 
84         return  value 
85     
86     return None
87
88
89 #===============================================================
90 # Extracts list of values following specified 'key' from 'args[]'
91 #===============================================================
92 def extract_list (key, args) : 
93
94     lenght = len(args)
95     if ( args is None or lenght == 0 ):
96         error_exit()
97
98     list=[]
99     found = 0
100
101     for i in  range(0, length) :
102         if args[i] == key  : 
103             if (is_key ( args[i+1]))  : 
104                  error_exit();
105             
106             for i in range (i+1, lenght):
107                 if is_key(args[i]) : break
108                 list.append(args[i])
109             found =1; break
110      
111     return list; #empty list is returned if no values after key
112
113
114 #==============================================================
115 # Method find the $key in the list and return 1 if success
116 # and 0 otherwise. 
117 #==============================================================
118 def find_key (key, argv) :
119
120     if (not is_key(key)) : return 0
121
122     for simbol in  argv :
123         if simbol == key:
124             return 1 
125     return 0
126
127 #==============================================================
128 # Parse the list of parameters
129 #==============================================================
130 def parse_parameters (args) :
131
132     if find_key('-h', args) :
133         print get_help_info();
134         import sys
135         sys.exit(0)
136         
137     xmlfile = extract_parameter("-f", args)
138     target_dir =  extract_parameter("-t", args)
139     tmp_dir = extract_parameter("-tmp", args)
140     if find_key('-b', args):
141         is_gui = 0
142     else : is_gui = 1
143     return [xmlfile, target_dir,  tmp_dir, is_gui]
144
145
146 #=================================================================
147 # The first algorithm to create the dependencies list by their level
148 #=================================================================
149 def get_next_level(list, products):
150     
151     import re
152     result = []
153     expr = "(" + list[0].name
154     for i in range(1, len(list)):
155         expr = expr + "|"+ list[i].name
156     
157     expr = expr + ")$"
158     #expr=re.compile(expr)
159
160     for product in products:
161         deps = re.sub(r'\s+', "", product.dependencies)
162         if re.search(expr,  deps):
163             result.append(product)
164
165     return result
166
167
168 def create_levels(prods):
169     import copy
170     
171     products = copy.deepcopy(prods)
172     
173     result = {}
174     import re
175     #1. find the products with empty lists of dependencies
176     list = []
177     for product in products:
178         if len(re.sub(r'\s', "", product.dependencies)) == 0 :
179             list.append(product)
180
181     if len(list) == 0 :
182         raise RuntimeError, "Products that depend on nothing are not found"
183
184     # remove the first level products from the common list of products
185     for product in list :
186         products.remove(product)
187
188     ind = 0; 
189     result[0] = list
190
191     while (len(products)) :
192         res = get_next_level(list, products)
193         if len(res) == 0 :
194             raise RuntimeError, "Empty list of products is found"
195
196         for product in res :
197             products.remove(product)
198
199         ind = ind +1
200         result[ind] =  res
201         list = res
202             
203     str = ""
204     for i in result.keys():
205         for product in  result[i]:
206             str = str + product.name + " "
207
208     return str;
209             
210 #=================================================================
211 # The second algorithm
212 #=================================================================
213 def get_dependencies_set(prods) :
214     import copy
215     import re
216
217     products = copy.deepcopy(prods)
218     deps = ""
219     list = []
220
221     while (len(products)) :
222
223         tmplist = []
224         #find the products with empty list of dependencies
225         for product in products:
226             product.dependencies = re.sub(r'\s+$', "", product.dependencies)
227             product.dependencies = re.sub(r'^\s+', "", product.dependencies)
228            
229             if len(product.dependencies) == 0 :
230                tmplist.append(product); 
231                deps = deps + " " + product.name
232
233         list.append(tmplist)
234
235         #remove the products names from other products dependencies
236         for item in tmplist:
237             products.remove(item)
238
239             regexpr1 = "((^|,(\s+)?)"+item.name+"$|^"+item.name+"(\s+)?,(\s+)?)"
240             regexpr2 = ",(\s+)?"+item.name+"(\s+)?,(\s+)?"
241
242             for product in products:
243                 product.dependencies = re.sub(r'\s+$', "", product.dependencies)
244                 product.dependencies = re.sub(r'^\s+', "", product.dependencies)
245
246                 product.dependencies = re.sub(regexpr1, "", product.dependencies)
247                 product.dependencies = re.sub(regexpr2, ",", product.dependencies)
248
249     return deps 
250     
251 #==============================================================
252 # Creates dir, returns the part of path that existed early.
253 # Access may be defined.
254 #==============================================================
255 def create_dir (directory, access = 0777):
256     import string, os
257     dirs = string.split(directory, "/")
258     existing = ""; dir = ""
259     root = ""
260     for item in dirs:
261         if len(item) == 0:  continue
262         dir = dir + "/"+item
263         if os.path.exists(dir):
264             existing = dir
265         else:
266             os.mkdir(dir, access )
267             #root= existing + "/"+item
268             if dir == existing + "/"+item :
269                 root = dir
270             #else : root = existing
271     
272     return root
273
274 #==============================================================
275 # class Product 
276 #==============================================================
277
278 class Product :
279     def __init__(self, theName,
280                  theVersion            = None,
281                  theInstall            = None,
282                  theSupportred         = None,
283                  theDisable            = None,
284                  theDependencies       = None,
285                  theInstalldiskspace   = None,
286                  theTemporarydiskspace = None,
287                  theScript             = None):
288         
289
290         self.name               = theName
291         self.version            = theVersion
292         self.install            = theInstall
293         self.supported          = theSupportred
294         self.disable            = theDisable
295         self.dependencies       = theDependencies
296         self.installdiskspace   = theInstalldiskspace
297         self.temporarydiskspace = theTemporarydiskspace
298         self.script             = theScript
299
300 #===================================================================
301 # class Config
302 #===================================================================
303 class Config :
304     def __init__(self, theVersion='', theCaption='', theCopyright='', theLicense='', theOS=''):
305         self.version   = theVersion
306         self.caption   = theCaption
307         self.copyright = theCopyright
308         self.license   = theLicense
309         self.os        = theOS
310
311
312 #===================================================================
313 # class Path
314 #===================================================================
315 class Path :
316     def __init__(self, theTargetdir=".", theTmpdir="."):
317         self.targetdir = theTargetdir
318         self.tmpdir    = theTmpdir
319
320         
321 #===================================================================
322 # class ConfigParser
323 #===================================================================
324 class ConfigParser(xmllib.XMLParser):
325     def __init__(self):
326         xmllib.XMLParser.__init__(self)
327         self.products = []
328         self.currentdata = []
329         self.path = None
330         self.config = None
331         
332     def handle_data(self, data):
333         self.currentdata.append(data)
334         
335     def start_product(self, attrs):
336         aProduct = Product(attrs['name'],
337                            attrs['version'],
338                            attrs['install'],
339                            attrs['supported'],
340                            attrs['disable'],
341                            attrs['dependancies'],
342                            attrs['installdiskspace'],
343                            attrs['temporarydiskspace'],
344                            attrs['script'])
345
346         self.products.append(aProduct)
347
348     def end_product(self):
349         pass
350
351     def start_config(self, attrs):
352         self.config = Config(attrs['version'],
353                              attrs['caption'],
354                              attrs['copyright'],
355                              attrs['license'],
356                              attrs['os'])
357     def end_config(self):
358         pass
359
360     def start_path (self, attrs):
361         self.path = Path(attrs['targetdir'],
362                          attrs['tempdir'])
363         print self.path.tmpdir
364         
365     def end_path(self):
366         pass
367
368 #================================================================
369 # get the path using file name
370 #================================================================
371 def get_current_path(file_name):
372     path = "."; where = string.rfind(file_name,'/');
373     if (where != -1):
374         path = (file_name)[: where]
375         os.chdir(path);
376     path = os.getcwd() + "/"
377     return path
378
379 #================================================================
380 # checks dir existing 
381 #================================================================
382 def check_dir(dir):
383     if (os.path.islink(dir)) :
384         native_dir = os.readlink(dir)
385         if not os.path.exists(native_dir) :
386             print "Bad link " + native_dir + " to directory " + native_dir + ". The last does not exist."
387             return 0 # problem
388     else :
389         if not os.path.exists(dir):
390             print "Directory " + dir + " does not exist"
391             return 0
392     return 1
393
394 #===============================================================
395 # Checks the disk space. Exit from interpreter if there is no
396 # enough disk space.
397 #===============================================================
398 def check_disk_space(products, script_dir, target_dir, tmp_dir):
399     import re, string, os
400     install_space = 0
401     temporary_space = 0
402     for product in products :
403         product.install = re.sub(r'^\s+', "", product.install)
404         product.install = re.sub(r'\s+$', "", product.install)
405         
406         if product.disable == "true" or product.install == "use native":
407             continue
408         spaces = string.split( product.installdiskspace,',')
409         prod_space = spaces[0]
410         if (len(spaces) == 2 ) and (product.install == "install binaries") :
411             prod_space = spaces[1]
412         install_space = install_space + string.atoi(prod_space)
413         temporary_space = temporary_space + string.atoi(product.temporarydiskspace)
414     res = os.system(scripts_dir + "checkSize.sh" + " " + target_dir + " " + str(install_space))
415     if res:
416         print "There is no enough space to install the products."
417         return 0
418     
419     res = os.system(scripts_dir + "checkSize.sh" + " " + tmp_dir + " " + str(temporary_space))
420     if res:
421         print "There is no enough space for tmp directory."
422         return 0
423     
424     return 1
425  
426
427 #================================================================
428 # main
429 #================================================================
430     
431 if __name__ == "__main__":
432     
433     cur_dir = get_current_path(sys.argv[0])
434    
435     [xml_file, target_dir, tmp_dir, is_gui]  = parse_parameters(sys.argv)
436
437     # define xml file -----------------
438     if (xml_file is None) :
439         xml_file_name = "config.xml"
440         if os.path.exists("/proc/version"):
441             data = open("/proc/version").readline()
442             res = re.search(r'Red\s+Hat\s+\w+(\s+)?(\d[.]\d)', data)
443             if res is not None:
444                 num = re.sub("[.]", "_", (res.groups())[1])
445                 filename = "config_RedHat" + num+ ".xml"
446                 if (os.path.exists(cur_dir + filename)):
447                     xml_file_name = filename
448                 
449         xml_file = cur_dir +  xml_file_name
450     if xml_file is None or not os.path.exists(xml_file):
451         error_exit("No xml file is found try to run with options -f <xmlfile>")
452
453     if not os.access(xml_file, os.R_OK):
454         print "There is no acceess to read "+ xml_file
455         sys.exit(1)
456
457     #---- GUI ----------------
458     if is_gui : 
459         env = os.environ
460         if not env.has_key("PATH") :
461             env["PATH"] = ""
462         if not env.has_key("LD_LIBRARY_PATH") :
463             env["LD_LIBRARY_PATH"]=  ""
464
465         env["LD_LIBRARY_PATH"] =  ".:" +  env["LD_LIBRARY_PATH"]
466         env["PATH"] = ".:"+ env["PATH"]
467
468         sys.exit(os.system("cd " + cur_dir + "; ./bin/SALOME_InstallWizard " + xml_file +"&"))
469         
470         
471
472     #-----  TUI ---------------------
473
474     #print xml_file, target_dir, tmp_dir, is_gui
475     
476     filehandle = open(xml_file)
477     data = filehandle.read()
478     filehandle.close()
479     parser = ConfigParser()
480     parser.feed(data)
481     parser.close()
482
483     # definitions :
484     # map
485     what_to_do = { "install sources":"install_source",
486                    "install binaries":"install_binary",
487                    "use native":"try_native"}
488     # define tmp dir  -----------
489     if tmp_dir is None:
490         tmp_dir = parser.path.tmpdir
491     root_path = ""
492     if not os.path.exists(tmp_dir):
493         print "Creating " + tmp_dir; root_path = create_dir(tmp_dir) ; 
494         import random
495         tmp_dir = tmp_dir + "/INSTALLWORK" + str(random.randint(10000,100000))
496         create_dir(tmp_dir,0755)
497         if not os.path.exists(tmp_dir):
498             error_exit("There is no tmp directory " + tmp_dir + ". Use -tmp key to set directory or correct xml file\n\n")
499
500     if not os.access(tmp_dir, os.W_OK) :
501         str = "We have no write permissions for directory " + tmp_dir + ". Use -tmp key to set directory or correct xml file"
502         error_exit(str)
503         
504     # define target dir  --------
505     if target_dir is None:
506         target_dir = parser.path.targetdir
507
508     if not os.path.exists(target_dir):
509         print "Creating " + target_dir; create_dir(target_dir, 0755)
510         if not os.path.exists(target_dir):
511             error_exit("There is no target directory " + target_dir + ". Use -t key to set directory or correct xml file\n\n")
512
513     if not os.access(target_dir, os.W_OK) :
514         str = "We have no write permissions for directory " + target_dir + ". Use -t key to set directory or correct xml file"
515         error_exit(str)
516     
517
518     # define products dir ------------
519     source_dir =  cur_dir + "Products" ; 
520     if not check_dir(source_dir):
521         if len(root_path) and os.path.exists(root_path):
522             os.system("rm -r -f "+ root_path)
523         sys.exit(1)
524        
525     subdir = {"install sources"  : "SOURCES",
526               "install binaries" : "BINARIES/"+parser.config.os,
527               "use native": ""}
528
529
530     #  define scripts dir ------------
531     scripts_dir = cur_dir + "config_files/"
532     if not check_dir(scripts_dir):
533         if len(root_path) and os.path.exists(root_path):
534             os.system("rm -r -f "+ root_path)
535         sys.exit(1)
536     os.chdir(scripts_dir)
537
538     list_of_dep =  create_levels(parser.products)
539     #list_of_dep =  get_dependencies_set(parser.products)
540
541     if check_disk_space(parser.products, scripts_dir, target_dir, tmp_dir) :
542  
543         for product in parser.products :
544
545             if product.disable == "true": continue
546
547             cmd = scripts_dir +  product.script + " " + \
548                   what_to_do[product.install]+ " " + \
549                   tmp_dir + " " + \
550                   source_dir + "/" + subdir[product.install] + " " + \
551                   target_dir + " " + \
552                   '"' + list_of_dep + '"' + " " + \
553                   product.name
554
555             res = os.system(cmd)
556             if res : break;
557
558     if len(root_path) and os.path.exists(root_path):
559         os.system("rm -r -f "+ root_path)