]> SALOME platform Git repositories - tools/install.git/blob - runInstall
Salome HOME
4a4796f8ec9d49e96befea1d3991293ccbfef473
[tools/install.git] / runInstall
1 #!/usr/bin/env python
2
3 import warnings
4 warnings.filterwarnings("ignore", "", DeprecationWarning)
5
6 import xmllib
7 import sys, os, string, re
8 from optparse import OptionParser
9
10 opt_parser = None
11 root_path  = None
12
13 __TAG__SOURCES__    = "install sources"
14 __TAG__BINARIES__   = "install binaries"
15 __TAG__NATIVE__     = "use native"
16 __TAG__PREINSTALL__ = "not install"
17
18 #==============================================================
19 # class Product 
20 #==============================================================
21
22 class Product :
23     def __init__(self,
24                  theName,
25                  theVersion            = None,
26                  theInstall            = None,
27                  theSupportred         = None,
28                  theDependencies       = None,
29                  theInstalldiskspace   = None,
30                  theTemporarydiskspace = None,
31                  theScript             = None,
32                  thePickUpEnvironment  = None):
33         self.name               = strip(theName)
34         self.version            = strip(theVersion)
35         self.install            = strip(theInstall)
36         self.supported          = strip(theSupportred)
37         self.dependencies       = strip(theDependencies)
38         self.installdiskspace   = strip(theInstalldiskspace)
39         self.temporarydiskspace = strip(theTemporarydiskspace)
40         self.script             = strip(theScript)
41         self.pickupEnv          = strip(thePickUpEnvironment)
42
43 #===================================================================
44 # class Config
45 #===================================================================
46 class Config :
47     def __init__(self,
48                  theVersion   = None,
49                  theCaption   = None,
50                  theCopyright = None,
51                  theLicense   = None,
52                  theOS        = None):
53         self.version   = strip(theVersion)
54         self.caption   = strip(theCaption)
55         self.copyright = strip(theCopyright)
56         self.license   = strip(theLicense)
57         self.os        = strip(theOS)
58
59 #===================================================================
60 # class Path
61 #===================================================================
62 class Path :
63     def __init__(self,
64                  theTargetdir = None,
65                  theTmpdir    = None):
66         self.targetdir = strip(theTargetdir)
67         self.tmpdir    = strip(theTmpdir)
68         
69 #===================================================================
70 # class ConfigParser
71 #===================================================================
72 class ConfigParser(xmllib.XMLParser):
73     def __init__(self):
74         xmllib.XMLParser.__init__(self)
75         self.products = []
76         self.currentdata = []
77         self.path = None
78         self.config = None
79         
80     def handle_data(self, data):
81         self.currentdata.append(data)
82         
83     def start_product(self, attrs):
84         if not attrs.get('name', '').strip():         return
85         if check_bool(attrs.get('disable', 'false')): return
86         aProduct = Product(attrs.get('name'),
87                            attrs.get('version',            None),
88                            attrs.get('install',            None),
89                            attrs.get('supported',          None),
90                            attrs.get('dependancies',       None),
91                            attrs.get('installdiskspace',   None),
92                            attrs.get('temporarydiskspace', None),
93                            attrs.get('script',             None),
94                            attrs.get('pickupenv',          None))
95         self.products.append(aProduct)
96         pass
97
98     def end_product(self):
99         pass
100
101     def start_config(self, attrs):
102         self.config = Config(attrs.get('version',   None),
103                              attrs.get('caption',   None),
104                              attrs.get('copyright', None),
105                              attrs.get('license',   None),
106                              attrs.get('os',        None))
107         pass
108     
109     def end_config(self):
110         pass
111
112     def start_path (self, attrs):
113         self.path = Path(attrs.get('targetdir', None),
114                          attrs.get('tempdir',   None))
115         pass
116         
117     def end_path(self):
118         pass
119
120     def getProduct(self, prod):
121         for product in self.products:
122             if product.name == prod:
123                 return product
124         return None
125
126 #==============================================================
127 # message: prints diagnostic information
128 #==============================================================
129 def message(msg):
130     if msg.strip():
131         print ">>>", msg
132     pass
133
134 #==============================================================
135 # warning: prints warning
136 #==============================================================
137 def warning(msg):
138     if msg.strip():
139         print ""
140         print msg
141         print ""
142     pass
143
144 #==============================================================
145 # error_exit : prints (optionally) error string, then prints
146 #              help information and quits
147 #==============================================================
148 def error_exit(msg = "", print_help = True):
149     # print error message
150     if len(msg.strip()):
151         print ""
152         print msg
153         print ""
154     # print help information
155     if print_help:
156         global opt_parser
157         if opt_parser:
158             opt_parser.print_help() 
159             print ""
160     # cleaning 
161     clean_all()
162     # quit
163     sys.exit(1);
164     pass
165
166 #==============================================================
167 # clean_all : performs system cleaning before exiting
168 #==============================================================
169 def clean_all():
170     global root_path
171     remove_dir(root_path)
172     pass
173
174 #==============================================================
175 # parse_parameters : parses command line arguments
176 #==============================================================
177 def parse_parameters():
178     global opt_parser
179     opt_parser = OptionParser(add_help_option=False)
180     help_str  = "Runs the Installation Wizard in the GUI mode [default].\n"
181     help_str += "In this case only -f option is taken into account. "
182     help_str += "Other options are ignored."
183     opt_parser.add_option("-g",
184                           "--gui",
185                           action="store_true",
186                           dest="gui",
187                           default=True,
188                           help=help_str)
189     help_str  = "Runs the Installation Wizard in the TUI mode."
190     opt_parser.add_option("-b",
191                           "--batch",
192                           action="store_false",
193                           dest="gui",
194                           help=help_str)
195     help_str  = "The configuration xml file.\n"
196     help_str += "If this parameter is missing, then the program tries to define the "
197     help_str += "Linux platform and use the corresponding xml file. For example, "
198     help_str += "for Red Hat 8.0 config_RedHat_8.0.xml file is used in this case."
199     help_str += "If program fails to define target Linux platform or the corresponding "
200     help_str += "xml file is not provided with the Installation Wizard, then default "
201     help_str += "config.xml file is used."
202     opt_parser.add_option("-f",
203                           "--file",
204                           action="store",
205                           dest="xmlfile",
206                           metavar="FILE",
207                           help=help_str)
208     help_str  = "The target directory the products to be installed to.\n"
209     help_str += "When used this parameter overrides the default target directory "
210     help_str += "defined in the configuration xml file."
211     opt_parser.add_option("-d",
212                           "--target",
213                           action="store",
214                           dest="target_dir",
215                           metavar="DIR",
216                           help=help_str)
217     help_str  = "The directory used for temporary files.\n"
218     help_str += "When used this parameter overrides the default temporary directory "
219     help_str += "defined in the configuration xml file."
220     opt_parser.add_option("-t",
221                           "--tmp",
222                           action="store",
223                           dest="tmp_dir",
224                           metavar="DIR",
225                           help=help_str)
226     help_str  = "Prints this help and quits."
227     opt_parser.add_option("-v",
228                           "--version",
229                           action="store_true",
230                           help=help_str)
231     help_str  = "Prints version information and quits."
232     opt_parser.add_option("-h",
233                           "--help",
234                           action="store_true",
235                           help=help_str)
236     (options, args) = opt_parser.parse_args()
237     if options.help:
238         # print help info and quit
239         print "\nSALOME Installation Wizard\n"
240         opt_parser.print_help()
241         print ""
242         sys.exit(0)
243     if options.version:
244         # print version info and quit
245         print ""
246         cmd = "./bin/SALOME_InstallWizard --version"
247         os.system(cmd)
248         print ""
249         sys.exit(0)
250     return [options.xmlfile, options.target_dir, options.tmp_dir, options.gui]
251
252 #=================================================================
253 # strip : removes spaces at the beginning and at eh end of the 
254 #         <param> if it is of string type
255 #=================================================================
256 def strip(param):
257     import types
258     if type(param) == types.StringType:
259         return param.strip()
260     return param
261     
262 #=================================================================
263 # check_bool : checks boolean value: yes/no, true/false, 1/0
264 #=================================================================
265 def check_bool(val):
266     if str(val).lower().strip() in ["yes","true", "1"]:
267         return True
268     if str(val).lower().strip() in ["no","false", "0"]:
269         return False
270     try:
271         val = int(val)
272         return val != 0
273     except:
274         pass
275     return False
276
277 #=================================================================
278 # get_dependencies : extract products dependencies
279 #=================================================================
280 def get_dependencies(prods):
281     list = []
282     for product in prods:
283         deps = product.dependencies.split(",")
284         for dep in deps:
285             if dep and not dep in list:
286                 list.append( dep )
287                 
288         if product and not product in list:
289             list.append( product.name )
290             
291     return " ".join( list )
292
293 #==============================================================
294 # create_dir : creates a directory with (optional) permissions,
295 #              returns the part of path that existed before
296 #              directory creation; exits with error if access
297 #              is denied
298 #==============================================================
299 def create_dir(directory, access = 0777):
300     import string, os
301     dirs = string.split(directory, "/")
302     existing = "";
303     dir = ""
304     root = ""
305     for subdir in dirs:
306         if len(subdir) == 0:  continue
307         dir = "%s/%s"%(dir, subdir)
308         if os.path.exists(dir):
309             existing = dir
310         else:
311             try:
312                 os.mkdir(dir, access)
313             except:
314                 error_exit("Can't create directory: %s.\nAccess is denied."%directory)
315             if dir == "%s/%s"%(existing, subdir):
316                 root = dir
317     return root
318
319 #==============================================================
320 # substituteVars : performes environment variables substistution
321 #                  the given string; if varibale is not defined
322 #                  it is substituted by the empty string
323 #==============================================================
324 def substituteVars(str):
325     str = os.path.expanduser(str)
326     str = os.path.expandvars(str)
327     return str
328
329 #================================================================
330 # get_program_path : gets program's directory path
331 #                    (and performs 'cd' command there) 
332 #================================================================
333 def get_program_path():
334     path = os.path.dirname(sys.argv[0])
335     if path:
336         os.chdir(path)
337     return os.getcwd()
338
339 #================================================================
340 # check_dir : checks directory existence
341 #================================================================
342 def check_dir(dir):
343     if (os.path.islink(dir)):
344         realpath = os.path.realpath(dir)
345         if not os.path.exists(realpath):
346             msg = "Invalid link %s.\nThe directory %s a link points to does not exist."%(dir,realpath)
347             error_exit(msg, False)
348     else:
349         if not os.path.exists(dir):
350             msg = "Directory %s does not exist."%dir
351             error_exit(msg, False)
352     pass
353
354 #===============================================================
355 # check_disk_space : checks the disk space;
356 #                    quits if there is no enough disk space
357 #===============================================================
358 def check_disk_space(products, scripts_dir, target_dir, tmp_dir):
359     install_space = 0
360     temporary_space = 0
361     for product in products:
362         if product.install in [__TAG__NATIVE__, __TAG__PREINSTALL__]:
363             continue
364         spaces = string.split(product.installdiskspace, ',')
365         prod_space = spaces[0]
366         if (len(spaces) > 1 ) and (product.install == __TAG__SOURCES__):
367             prod_space = spaces[1]
368         install_space = install_space + string.atoi(prod_space)
369         if product.install == __TAG__SOURCES__:
370             temporary_space = max(temporary_space, string.atoi(product.temporarydiskspace))
371
372     res = os.system("%s/%s %s %d"%(scripts_dir, "checkSize.sh", target_dir, install_space))
373     if res:
374         msg = "There is no enough space to install the products."
375         error_exit(msg, False)
376     
377     res = os.system("%s/%s %s %d"%(scripts_dir, "checkSize.sh", tmp_dir, temporary_space))
378     if res:
379         msg = "There is no enough space for temporary directory."
380         error_exit(msg, False)
381     pass
382  
383 #===============================================================
384 # remove_dir : removes temporary directory
385 #===============================================================
386 def remove_dir(path):
387     if path and os.path.exists(path):
388         os.system("rm -rf " + path)
389     pass
390
391 #==============================================================
392 # has_binaries : returns True if some product is installed from
393 #                binaries
394 #===============================================================
395 def has_binaries(products):
396     for product in products:
397         if product.install == __TAG__BINARIES__:
398             return True
399     return False
400
401 #==============================================================
402 # has_sources : returns True if some product is installed from
403 #               sources
404 #===============================================================
405 def has_sources(products):
406     for product in products:
407         if product.install == __TAG__SOURCES__:
408             return True
409     return False
410
411 #================================================================
412 # main
413 #================================================================
414     
415 if __name__ == "__main__":
416     # get program dir
417     cur_dir = get_program_path()
418     # parse command line
419     [xml_file, target_dir, tmp_dir, is_gui] = parse_parameters()
420
421     # define xml file to be used
422     if (xml_file is None):
423         plt_name = ""
424         plt_ver  = ""
425         xml_file_name = "config.xml"
426         if os.path.exists("/etc/redhat-release"):
427             # - Red Hat Linux 8.0
428             # - Red Hat Linux 9
429             # - Mandrake Linux 10.1
430             # - Scientific Linux 3.0.5
431             data = open("/etc/redhat-release").readline()
432             res = re.search(r'(.*)[L|l]inux.*release\s+([\d.]*)', data)
433             if res:
434                 plt_name = "".join(res.group(1).split())
435                 plt_ver  = res.group(2)
436         elif os.path.exists("/etc/debian_version"):
437             # - Debian 3.1
438             plt_name = "Debian"
439             plt_ver = open("/etc/debian_version").readline().strip()
440         _xml_file_name = "config_%s_%s.xml"%(plt_name, plt_ver)
441         if plt_name and plt_ver and os.path.exists("%s/%s"%(cur_dir, _xml_file_name)):
442             xml_file_name = _xml_file_name
443         else:
444             msg  = "Not supported Linux platform!\n"
445             msg += "Trying to use default configuration file!"
446             warning(msg)
447
448         xml_file = "%s/%s"%(cur_dir, xml_file_name)
449
450     if not xml_file or not os.path.exists(xml_file):
451         msg = "Configuration file %s is not found!"%xml_file
452         error_exit(msg)
453
454     if not os.access(xml_file, os.R_OK):
455         msg = "There is no read access for %s file!"%xml_file
456         error_exit(msg)
457
458     #---- GUI ----------------
459
460     if is_gui : 
461         env = os.environ
462         if not env.has_key("PATH") :
463             env["PATH"] = ""
464         if not env.has_key("LD_LIBRARY_PATH") :
465             env["LD_LIBRARY_PATH"] = ""
466
467         env["LD_LIBRARY_PATH"] =  ".:" + env["LD_LIBRARY_PATH"]
468         env["PATH"] = ".:" + env["PATH"]
469
470         cmd = "./bin/SALOME_InstallWizard %s &"%xml_file
471         sys.exit(os.system(cmd))
472
473     #-----  TUI ---------------------
474
475     # parse XML file -----------
476     message("Parsing XML configuration file: %s"%xml_file)
477     filehandle = open(xml_file)
478     data = filehandle.read()
479     filehandle.close()
480     parser = ConfigParser()
481     parser.feed(data)
482     parser.close()
483
484     # actions map
485     what_to_do = { __TAG__SOURCES__    : "install_source",
486                    __TAG__BINARIES__   : "install_binary",
487                    __TAG__NATIVE__     : "try_native",
488                    __TAG__PREINSTALL__ : "try_preinstalled"}
489     # source directory map
490     bin_dir = ""
491     if parser.config.os:
492         bin_dir += "/%s"%parser.config.os
493     subdir = { __TAG__SOURCES__    : "SOURCES",
494                __TAG__BINARIES__   : "BINARIES" + bin_dir,
495                __TAG__NATIVE__     : "",
496                __TAG__PREINSTALL__ : ""}
497
498     # check scripts directory -----------
499     scripts_dir = "%s/%s"%(cur_dir, "config_files")
500     check_dir(scripts_dir)
501
502     # check products archives directories -----------
503     has_bin = has_binaries(parser.products)
504     has_src = has_sources(parser.products)
505     source_dir = "%s/%s"%(cur_dir, "Products")
506
507     if has_src or has_bin:
508         check_dir(source_dir)
509
510     if has_src:
511         check_dir("%s/%s"%(source_dir,subdir[__TAG__SOURCES__]))
512
513     if has_bin:
514         check_dir("%s/%s"%(source_dir,subdir[__TAG__BINARIES__]))
515
516     # check/create target dir -----------
517     if target_dir is None:
518         target_dir = parser.path.targetdir
519     target_dir = substituteVars(target_dir)
520
521     message("Creating target directory: " + target_dir)
522     create_dir(target_dir, 0755)
523
524     if not os.path.exists(target_dir):
525         error_exit("Invalid target directory: " + target_dir)
526
527     if not os.access(target_dir, os.W_OK) :
528         error_exit("There is no write permissions for the directory: " + target_dir)
529
530     # check/create temporary dir -----------
531     if tmp_dir is None:
532         tmp_dir = parser.path.tmpdir
533     if not tmp_dir:
534         tmp_dir = "/tmp"
535     tmp_dir = substituteVars(tmp_dir)
536     import random
537     tmp_dir = "%s/INSTALLWORK%d"%(tmp_dir, random.randint(10000,100000))
538
539     message("Creating temporary directory: " + tmp_dir)
540     root_path = create_dir(tmp_dir, 0755)
541    
542     if not os.path.exists(tmp_dir):
543         error_exit("Invalid temporary directory: " + tmp_dir)
544
545     if not os.access(tmp_dir, os.W_OK) :
546         error_exit("There is no write permissions for the directory: " + tmp_dir)
547         
548     # check available disk space
549     message("Checking available disk space")
550     check_disk_space(parser.products, scripts_dir, target_dir, tmp_dir)
551
552     # change current directory
553     os.chdir(scripts_dir)
554
555     # get dependencies list
556     list_of_dep = get_dependencies(parser.products)
557
558     # starting
559     message("Starting ...")
560     
561     # install products
562     for product in parser.products:
563         message("... processing %s ..."%product.name)
564         cmd = '%s/%s %s %s %s/%s %s "%s" %s'%(scripts_dir,
565                                               product.script,
566                                               what_to_do[product.install],
567                                               tmp_dir,
568                                               source_dir,
569                                               subdir[product.install],
570                                               target_dir,
571                                               list_of_dep,
572                                               product.name)
573         res = os.system(cmd)
574
575     # pickup environment
576     message("Creating environment files")
577     for product in parser.products :
578         if check_bool(product.pickupEnv):
579             cmd = '%s/%s pickup_env %s %s/%s %s "%s" %s'%(scripts_dir,
580                                                           product.script,
581                                                           tmp_dir,
582                                                           source_dir,
583                                                           subdir[product.install],
584                                                           target_dir,
585                                                           list_of_dep,
586                                                           product.name)
587             res = os.system(cmd)
588
589     # clean temporary directory
590     message("Cleaning temporary directory")
591     clean_all()
592     # finishing
593     message("Finished!")
594     pass