Salome HOME
Improve for 64bit platforms
[tools/install.git] / runInstall
1 #!/usr/bin/env python
2
3 """
4 Installation Wizard launching script.
5 """
6
7 __version__ = "1.0.1"
8
9 # --- avoid "deprecation" warnings --- #
10 import warnings
11 warnings.filterwarnings("ignore", "", DeprecationWarning)
12
13 # --- imports --- #
14 import xmllib
15 import sys, os, string, re
16 import types
17 import random
18
19 # --- global variables --- #
20 opt_parser = None
21 root_path  = None
22
23 # --- XML tags definition --- #
24 __TAG__SOURCES__    = "install sources"
25 __TAG__BINARIES__   = "install binaries"
26 __TAG__NATIVE__     = "use native"
27 __TAG__PREINSTALL__ = "not install"
28
29 #------------------------------------------------------------------#
30 #                                                                  #
31 #                 COMMAND LINE ARGUMENTS PARSER                    #
32 #                                                                  #
33 #------------------------------------------------------------------#
34
35 #===================================================================
36 # class OptBaseError : base parse error
37 #===================================================================
38 class OptBaseError(Exception):
39     """
40     Base option parsing exception class
41     """
42     def __init__(self, msg):
43         self.msg = msg
44     def __str__ (self):
45         return self.msg
46
47 #===================================================================
48 # class OptError : bad option error
49 #===================================================================
50 class OptError(OptBaseError):
51     """
52     Bad option exception class
53     """
54     def __init__ (self, msg, option):
55         self.msg = msg
56         self.option = option
57     def __str__ (self):
58         if self.option:
59             opt_prs = "<unknown>"
60             if self.option.short_opt and self.option.long_opt:
61                 opt_prs = "%s/%s"%(self.option.short_opt,self.option.long_opt)
62             elif self.option.short_opt:
63                 opt_prs = "%s"%(self.option.short_opt)
64             elif self.option.long_opt:
65                 opt_prs = "%s"%(self.option.long_opt)
66             return "option %s: %s"%(opt_prs, self.msg)
67         return self.msg
68
69 #===================================================================
70 # class ArgError : bad option argument error
71 #===================================================================
72 class ArgError(OptBaseError):
73     """
74     Bad argument exception class
75     """
76     pass
77
78 #===================================================================
79 # class ValError : bad command line parameter error
80 #===================================================================
81 class ValError(OptBaseError):
82     """
83     Bad parameter exception class
84     """
85     pass
86
87 #===================================================================
88 # class ArgOption : command line option
89 #===================================================================
90 class ArgOption:
91     """
92     Option class
93     """
94     attrs   = ["short_opt", "long_opt", "dest", "action", "type", "default", "metavar", "help"]
95     actions = ["store", "store_true", "store_false"]
96     types   = ["string", "int", "float", "bool"]
97     def __init__(self, *args, **kwargs):
98         # set defaults
99         for attr in self.attrs: setattr(self, attr, None)
100         # parse arguments
101         for i in range(len(args)):
102             if i > len(self.attrs)-1:
103                 msg = "Wrong number of parameters is given (maximum is %d)" % len(self.attrs)
104                 raise OptBaseError(msg)
105             setattr(self, self.attrs[i], args[i])
106         for arg in kwargs:
107             if arg not in self.attrs:
108                 msg = "Invalid argument: %s" % arg
109                 raise OptBaseError(msg)
110             setattr(self, arg, kwargs[arg])
111         # check short option key
112         if self.short_opt and \
113                not re.match("^-[a-zA-Z]$",self.short_opt):
114             msg  = "invalid short option key; "
115             msg += "should be of the form -x (x is letter)"
116             raise OptError(msg, self)
117         # check long option key
118         if self.long_opt and \
119                not re.match("^--[a-zA-Z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$",self.long_opt):
120             msg  = "invalid long option key; "
121             msg += "should be of the form --word[[-word]...] "
122             msg += "(word is letters and digits sequence)"
123             raise OptError(msg, self)
124         # check that at least one option key is defined
125         if not self.short_opt and not self.long_opt:
126             msg  = "invalid option; neither short nor long option key is defined"
127             raise OptError(msg, self)
128         # destination
129         if not self.dest and self.long_opt:
130             self.dest = self.long_opt[2:].replace('-','_')
131         if not self.dest and self.short_opt:
132             self.dest = self.short_opt[1:]
133         # action
134         if not self.action:
135             self.action = "store"
136         if self.action not in self.actions:
137             msg  = "invalid action: %s" % self.action
138             raise OptError(msg, self)
139         # type
140         if not self.type:
141             if self.action in ["store_true","store_false"]: self.type = "bool"
142             else: self.type = "string"
143         if self.type not in self.types:
144             msg  = "invalid type: %s" % self.type
145             raise OptError(msg, self)
146         if self.action in ["store_true","store_false"] and self.type != "bool":
147             msg  = "invalid type: %s : should be 'bool' or None" % self.type
148             raise OptError(msg, self)
149         # default
150         if self.default:
151             try:
152                 if self.type == "string": self.default = str(self.default)
153                 if self.type == "int":    self.default = int(self.default)
154                 if self.type == "float":  self.default = float(self.default)
155                 if self.type == "bool":   self.default = boolean(self.default)
156             except :
157                 msg  = "invalid default value type: should be %s" % self.type
158                 raise OptError(msg, self)
159             pass
160         # metavar
161         if not self.metavar:
162             self.metavar = self.dest.upper()
163         # help
164         if not self.help:
165             self.help = ""
166         pass
167
168     def to_string(self):
169         """
170         Returns string representation of the option
171         """
172         opts = []
173         opt = self.short_opt
174         if opt and self.action == "store" and self.metavar: opt += " %s" % self.metavar
175         if opt: opts.append(opt)
176         opt = self.long_opt
177         if opt and self.action == "store" and self.metavar: opt += "=%s" % self.metavar
178         if opt: opts.append(opt)
179         return (", ").join(opts)
180     
181 #===================================================================
182 # class Values : resulting option values
183 #===================================================================
184 class Values:
185     """
186     Values class
187     """
188     def __init__(self):
189         pass
190         
191 #===================================================================
192 # class ArgParser : command line arguments parser
193 #===================================================================
194 class ArgParser:
195     """
196     Arguments parser class
197     """
198     def __init__(self):
199         self.options = []
200         pass
201
202     def add_option(self, *args, **kwargs):
203         """Register an option"""
204         o = ArgOption(*args, **kwargs)
205         self._check_option(o)
206         self.options.append(o)
207         pass
208
209     def parse_args(self, args = None):
210         """Parse an arguments"""
211         if not args: args = sys.argv[1:]
212         values = Values()
213         for o in self.options:
214             if o.default:
215                 setattr(values, o.dest, o.default)
216             elif not hasattr(values,o.dest):
217                 setattr(values, o.dest, None)
218         try:
219             (values, args) = self._process_args(values, args)
220         except (ArgError, ValError), e:
221             self._error(e.msg)
222
223         return (values, args)
224             
225     def print_usage(self):
226         """Print usage"""
227         print "usage: %s [options]" % os.path.basename(sys.argv[0])
228         pass
229
230     def print_help(self):
231         """Print help"""
232         self.print_usage()
233         print ""
234         olen = 0
235         _maxwidth, _indent = 79, 2
236         if len(self.options):
237             for option in self.options:
238                 if olen < len(option.to_string()): olen = len(option.to_string())
239             print "options:"
240             for option in self.options:
241                 strings = []
242                 for hs in option.help.split("\n"):
243                     s = ""
244                     for w in hs.split():
245                         if len("%s %s" % (s,w)) > _maxwidth:
246                             strings.append(s.strip()); s = ""
247                         s = "%s %s" % (s,w)
248                     if s.strip(): strings.append(s.strip())
249                 if not strings: strings[:0] = [""]
250                 print "%s%s%s" % (option.to_string(), " "*(_indent+olen-len(option.to_string())), strings[0])
251                 for i in range(1, len(strings)):
252                     print "%s%s" % (" "*(olen+_indent), strings[i])
253         pass
254     
255     def _check_option(self, option):
256         o = self._get_option(option.short_opt)
257         if not o: o = self._get_option(option.long_opt)
258         if o:
259             msg = "option conflicts with previously defined option(s)"
260             raise OptError(msg, option)
261         pass
262
263     def _get_option(self, opt_key):
264         if opt_key:
265             for o in self.options:
266                 if opt_key in [o.short_opt, o.long_opt]: return o
267         return None
268         
269     def _error(self, msg):
270         self.print_usage()
271         sys.exit("\n%s: error: %s\n" % (os.path.basename(sys.argv[0]), msg))
272         pass
273
274     def _check_value(self, option, value):
275         o = self._get_option(option)
276         try:
277             if o.type == "string": return str(value)
278             if o.type == "int":    return int(value)
279             if o.type == "float":  return float(value)
280             if o.type == "bool":   return boolean(value)
281         except:
282             msg  = "invalid value type for option %s: %s; " % (option, value)
283             msg += "should be %s" % o.type
284             raise ValError(msg)
285         raise OptBaseError("unknown error")
286
287     def _process_args(self, values, args):
288         res_args = []
289         cur_opt = None
290         rargs   = []
291         for index in range(len(args)):
292             a = args[index]
293             if cur_opt and cur_opt[1].action == "store":
294                 setattr(values, cur_opt[1].dest, self._check_value(cur_opt[0], a))
295                 cur_opt = None
296                 continue
297             if a == "-":
298                 rargs = args[index+1:]
299                 break
300             elif re.match("^-[a-zA-Z].*", a):
301                 for i in range(1,len(a)):
302                     if cur_opt and cur_opt[1].action == "store":
303                         setattr(values, cur_opt[1].dest, self._check_value(cur_opt[0], a[i:]))
304                         cur_opt = None
305                         break
306                     o = self._get_option("-%s"%a[i])
307                     if not o:
308                         raise ArgError("no such option: -%s"%a[i])
309                     if o.action == "store_true":
310                         setattr(values, o.dest, True)
311                     elif o.action == "store_false":
312                         setattr(values, o.dest, False)
313                     else:
314                         cur_opt = ("-%s"%a[i], o)
315                 pass
316             elif re.match("^--[a-zA-Z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*", a):
317                 oname  = ("%s="%a).split("=")[0]
318                 ovalue = ("%s="%a).split("=")[1]
319                 o = self._get_option(oname)
320                 if not o:
321                     raise ArgError("no such option: %s" % oname)
322                 if o.action == "store_true":
323                     if ovalue:
324                         raise ValError("option %s does not take a value" % oname)
325                     setattr(values, o.dest, True)
326                 elif o.action == "store_false":
327                     if ovalue:
328                         raise ValError("option %s does not take a value" % oname)
329                     setattr(values, o.dest, False)
330                 else:
331                     if ovalue:
332                         setattr(values, o.dest, self._check_value(oname, ovalue))
333                     else:
334                         cur_opt = (oname, o)
335                 pass
336             elif a.startswith("-"):
337                 raise ArgError("bad formatted option: %s" % a)
338             else:
339                 rargs = args[index:]
340                 break
341         if cur_opt and cur_opt[1].action == "store":
342             raise ValError("option %s requires value" % cur_opt[0])
343         return (values, rargs)
344
345 #------------------------------------------------------------------#
346 #                                                                  #
347 #                 XML CONFIGURATION FILES PARSER                   #
348 #                                                                  #
349 #------------------------------------------------------------------#
350
351 #===================================================================
352 # class Config : general configuration options : version, OS, etc...
353 #===================================================================
354 class Config :
355     """
356     General configuration file options:
357     - Install Wizard window caption
358     - SALOME platform version
359     - Copyright and libcense info
360     - Target Linux OS version
361     """
362     def __init__(self,
363                  theVersion   = None,
364                  theCaption   = None,
365                  theCopyright = None,
366                  theLicense   = None,
367                  theOS        = None):
368         self.version   = strip(theVersion)
369         self.caption   = strip(theCaption)
370         self.copyright = strip(theCopyright)
371         self.license   = strip(theLicense)
372         self.os        = strip(theOS)
373
374 #===================================================================
375 # class Path : default target, temporary directories options
376 #===================================================================
377 class Path :
378     """
379     Path options:
380     - default target directory
381     - default temporary directory
382     """
383     def __init__(self,
384                  theTargetdir = None,
385                  theTmpdir    = None):
386         self.targetdir = strip(theTargetdir)
387         self.tmpdir    = strip(theTmpdir)
388         
389 #==============================================================
390 # class Product : pre-requisite product options
391 #==============================================================
392 class Product :
393     """
394     Product options:
395     - name, version
396     - supported installation modes and the default one
397     - dependencies
398     - required disk space
399     - installation script
400     - etc...
401     """
402     def __init__(self,
403                  theName,
404                  theVersion            = None,
405                  theInstall            = None,
406                  theSupportred         = None,
407                  theDependencies       = None,
408                  theInstalldiskspace   = None,
409                  theTemporarydiskspace = None,
410                  theScript             = None,
411                  thePickUpEnvironment  = None):
412         self.name               = strip(theName)
413         self.version            = strip(theVersion)
414         self.install            = strip(theInstall)
415         self.supported          = strip(theSupportred)
416         self.dependencies       = strip(theDependencies)
417         self.installdiskspace   = strip(theInstalldiskspace)
418         self.temporarydiskspace = strip(theTemporarydiskspace)
419         self.script             = strip(theScript)
420         self.pickupEnv          = strip(thePickUpEnvironment)
421
422 #===================================================================
423 # class ConfigParser : XML files parser implementation
424 #===================================================================
425 class ConfigParser(xmllib.XMLParser):
426     """
427     XML configuration files parser
428     """
429     def __init__(self):
430         xmllib.XMLParser.__init__(self)
431         self.products = []
432         self.currentdata = []
433         self.path = None
434         self.config = None
435         
436     def handle_data(self, data):
437         self.currentdata.append(data)
438         
439     def start_product(self, attrs):
440         if not attrs.get('name', '').strip():         return
441         if check_bool(attrs.get('disable', 'false')): return
442         aProduct = Product(attrs.get('name'),
443                            attrs.get('version',            None),
444                            attrs.get('install',            None),
445                            attrs.get('supported',          None),
446                            attrs.get('dependancies',       None),
447                            attrs.get('installdiskspace',   None),
448                            attrs.get('temporarydiskspace', None),
449                            attrs.get('script',             None),
450                            attrs.get('pickupenv',          None))
451         self.products.append(aProduct)
452         pass
453
454     def end_product(self):
455         pass
456
457     def start_config(self, attrs):
458         self.config = Config(attrs.get('version',   None),
459                              attrs.get('caption',   None),
460                              attrs.get('copyright', None),
461                              attrs.get('license',   None),
462                              attrs.get('os',        None))
463         pass
464     
465     def end_config(self):
466         pass
467
468     def start_path (self, attrs):
469         self.path = Path(attrs.get('targetdir', None),
470                          attrs.get('tempdir',   None))
471         pass
472         
473     def end_path(self):
474         pass
475
476     def getProduct(self, prod):
477         for product in self.products:
478             if product.name == prod:
479                 return product
480         return None
481
482 #------------------------------------------------------------------#
483 #                                                                  #
484 #                         SERVICE FUNCTIONS                        #
485 #                                                                  #
486 #------------------------------------------------------------------#
487
488 #==============================================================
489 # message: prints diagnostic information
490 #==============================================================
491 def message(msg):
492     """
493     Prints diagnostic information.
494     """
495     if msg.strip():
496         print ">>>", msg
497     pass
498
499 #==============================================================
500 # warning: prints warning
501 #==============================================================
502 def warning(msg):
503     """
504     Prints warning.
505     """
506     if msg.strip():
507         print ""
508         print msg
509         print ""
510     pass
511
512 #==============================================================
513 # error_exit : prints (optionally) error string, then prints
514 #              help information and quits
515 #==============================================================
516 def error_exit(msg = "", print_help = True):
517     """
518     Prints (optionally) error string,
519     then prints help information and quits.
520     """
521     # print error message
522     if len(msg.strip()):
523         print ""
524         print msg
525         print ""
526     # print help information
527     if print_help:
528         global opt_parser
529         if opt_parser:
530             opt_parser.print_help() 
531             print ""
532     # cleaning 
533     clean_all()
534     # quit
535     sys.exit(1);
536     pass
537
538 #==============================================================
539 # boolean : Converts string to boolean value.
540 #==============================================================
541 def boolean(val):
542     """
543     Converts string to boolean value if possible.
544     Raises exception if wrong string is used.
545     """
546     if isinstance(val, types.StringType):
547         if val.strip().lower()   in ["true",  "yes", "ok"]     : return True
548         elif val.strip().lower() in ["false", "no",  "cancel"] : return False
549         else: raise TypeError("invalid boolean value")
550     return bool(val)
551
552 #=================================================================
553 # check_bool : checks boolean value: yes/no, true/false, 1/0
554 #=================================================================
555 def check_bool(val):
556     """
557     Checks boolean value.
558     """
559     try:
560         return boolean(val)
561     except:
562         pass
563     return False
564
565 #==============================================================
566 # clean_all : performs system cleaning before exiting
567 #==============================================================
568 def clean_all():
569     """
570     Performs system cleaning before exiting.
571     """
572     global root_path
573     remove_dir(root_path)
574     pass
575
576 #==============================================================
577 # parse_parameters : parses command line arguments
578 #==============================================================
579 def parse_parameters():
580     """
581     Parses command line arguments.
582     """
583     global opt_parser
584     opt_parser = ArgParser()
585     
586     help_str  = "Runs the Installation Wizard in the GUI mode [default].\n"
587     opt_parser.add_option("-g",
588                           "--gui",
589                           action="store_true",
590                           dest="gui",
591                           default=True,
592                           help=help_str)
593     help_str  = "Runs the Installation Wizard in the TUI mode."
594     opt_parser.add_option("-b",
595                           "--batch",
596                           action="store_false",
597                           dest="gui",
598                           help=help_str)
599     help_str  = "The configuration xml file.\n"
600     help_str += "If this parameter is missing, then the program tries to define the "
601     help_str += "Linux platform and use the corresponding xml file. For example, "
602     help_str += "for Red Hat 8.0 config_RedHat_8.0.xml file is used in this case. "
603     help_str += "If program fails to define target Linux platform or the corresponding "
604     help_str += "xml file is not provided with the Installation Wizard, then default "
605     help_str += "config.xml file is used."
606     opt_parser.add_option("-f",
607                           "--file",
608                           action="store",
609                           dest="xmlfile",
610                           metavar="FILE",
611                           help=help_str)
612     help_str  = "The target directory the products to be installed to.\n"
613     help_str += "When used this parameter overrides the default target directory "
614     help_str += "defined in the configuration xml file."
615     opt_parser.add_option("-d",
616                           "--target",
617                           action="store",
618                           dest="target_dir",
619                           metavar="DIR",
620                           help=help_str)
621     help_str  = "The directory to be used for temporary files.\n"
622     help_str += "When used this parameter overrides the default temporary directory "
623     help_str += "defined in the configuration xml file."
624     opt_parser.add_option("-t",
625                           "--tmp",
626                           action="store",
627                           dest="tmp_dir",
628                           metavar="DIR",
629                           help=help_str)
630     help_str  = "Prints version information and quits."
631     opt_parser.add_option("-v",
632                           "--version",
633                           action="store_true",
634                           help=help_str)
635     help_str  = "Prints this help and quits."
636     opt_parser.add_option("-h",
637                           "--help",
638                           action="store_true",
639                           help=help_str)
640     (options, args) = opt_parser.parse_args()
641     if options.help:
642         # print help info and quit
643         print "\nSALOME Installation Wizard\n"
644         opt_parser.print_help()
645         print ""
646         sys.exit(0)
647     if options.version:
648         # print version info and quit
649         print ""
650         cmd = "./bin/SALOME_InstallWizard --version"
651         os.system(cmd)
652         print ""
653         sys.exit(0)
654     return [options.xmlfile, options.target_dir, options.tmp_dir, options.gui]
655
656 #=================================================================
657 # strip : removes spaces at the beginning and at the end of the 
658 #         <param> if it is of string type
659 #=================================================================
660 def strip(param):
661     """
662     Removes spaces at the beginning and at the end
663     of the given parameter.
664     """
665     if type(param) == types.StringType:
666         return param.strip()
667     return param
668     
669 #=================================================================
670 # get_dependencies : extract products dependencies
671 #=================================================================
672 def get_dependencies(prods):
673     """
674     Gets full list of pre-requisite products.
675     """
676     list = []
677     for product in prods:
678         deps = product.dependencies.split(",")
679         for dep in deps:
680             if dep and not dep in list:
681                 list.append( dep )
682                 
683         if product and not product in list:
684             list.append( product.name )
685             
686     return " ".join( list )
687
688 #==============================================================
689 # create_dir : creates a directory with (optional) permissions,
690 #              returns the part of path that existed before
691 #              directory creation; exits with error if access
692 #              is denied
693 #==============================================================
694 def create_dir(directory, access = 0777):
695     """
696     Creates a directory with (optional) permissions,
697     returns the part of path that existed before
698     directory creation; exits with error if access
699     is denied.
700     """
701     dirs = string.split(directory, "/")
702     existing = "";
703     dir = ""
704     root = ""
705     for subdir in dirs:
706         if len(subdir) == 0:  continue
707         dir = "%s/%s"%(dir, subdir)
708         if os.path.exists(dir):
709             existing = dir
710         else:
711             try:
712                 os.mkdir(dir, access)
713             except:
714                 error_exit("Can't create directory: %s.\nAccess is denied."%directory)
715             if dir == "%s/%s"%(existing, subdir):
716                 root = dir
717     return root
718
719 #==============================================================
720 # substituteVars : performes environment variables substistution
721 #                  the given string; if varibale is not defined
722 #                  it is substituted by the empty string
723 #==============================================================
724 def substituteVars(str):
725     """
726     Performes environment variables substistution.
727     """
728     str = os.path.expanduser(str)
729     str = os.path.expandvars(str)
730     return str
731
732 #================================================================
733 # get_program_path : gets program's directory path
734 #                    (and performs 'cd' command there) 
735 #================================================================
736 def get_program_path():
737     """
738     Returns the program directory path
739     (and make this directory current).
740     """
741     path = os.path.dirname(sys.argv[0])
742     if path:
743         os.chdir(path)
744     return os.getcwd()
745
746 #================================================================
747 # check_dir : checks directory existence
748 #================================================================
749 def check_dir(dir):
750     """
751     Checks directory existence.
752     """
753     if (os.path.islink(dir)):
754         realpath = os.path.realpath(dir)
755         if not os.path.exists(realpath):
756             msg = "Invalid link %s.\nThe directory %s a link points to does not exist. Stopped..."%(dir,realpath)
757             error_exit(msg, False)
758     else:
759         if not os.path.exists(dir):
760             msg = "Directory %s does not exist. Stopped..."%dir
761             error_exit(msg, False)
762     pass
763
764 #===============================================================
765 # check_disk_space : checks the disk space;
766 #                    quits if there is no enough disk space
767 #===============================================================
768 def check_disk_space(products, scripts_dir, target_dir, tmp_dir):
769     """
770     Checks if there is enough disk space to install products.
771     Quits with error if there is no enough disk space.
772     """
773     install_space = 0
774     temporary_space = 0
775     for product in products:
776         if product.install in [__TAG__NATIVE__, __TAG__PREINSTALL__]:
777             continue
778         spaces = string.split(product.installdiskspace, ',')
779         prod_space = spaces[0]
780         if (len(spaces) > 1 ) and (product.install == __TAG__SOURCES__):
781             prod_space = spaces[1]
782         install_space = install_space + string.atoi(prod_space)
783         if product.install == __TAG__SOURCES__:
784             temporary_space = max(temporary_space, string.atoi(product.temporarydiskspace))
785
786     res = os.system("%s/%s %s %d"%(scripts_dir, "checkSize.sh", target_dir, install_space))
787     if res:
788         msg = "There is no enough space to install the products. Stopped..."
789         error_exit(msg, False)
790     
791     res = os.system("%s/%s %s %d"%(scripts_dir, "checkSize.sh", tmp_dir, temporary_space))
792     if res:
793         msg = "There is no enough space for temporary directory. Stopped..."
794         error_exit(msg, False)
795     pass
796  
797 #===============================================================
798 # remove_dir : removes temporary directory
799 #===============================================================
800 def remove_dir(path):
801     """
802     Removes temporary directory.
803     """
804     if path and os.path.exists(path):
805         os.system("rm -rf " + path)
806     pass
807
808 #==============================================================
809 # has_binaries : returns True if some product is installed from
810 #                binaries
811 #===============================================================
812 def has_binaries(products):
813     """
814     Returns True if some product is installed in 'binaries' mode.
815     """
816     for product in products:
817         if product.install == __TAG__BINARIES__:
818             return True
819     return False
820
821 #==============================================================
822 # has_sources : returns True if some product is installed from
823 #               sources
824 #===============================================================
825 def has_sources(products):
826     """
827     Returns True if some product is installed in 'sources' mode.
828     """
829     for product in products:
830         if product.install == __TAG__SOURCES__:
831             return True
832     return False
833
834 #==============================================================
835 # get_tmp_dir : gets temporary directory name
836 #===============================================================
837 def get_tmp_dir(dir):
838     """
839     Gets temporary directory path.
840     """
841     max_attempts = 100
842     dir_prefix="INSTALLWORK"
843     range_bottom = 0; range_top = 999999
844     for i in xrange(max_attempts):
845         tmp_dir = "%s/%s%d"%(dir, dir_prefix, random.randint(range_bottom,range_top))
846         if not os.path.exists( tmp_dir ):
847             return tmp_dir
848     return "%s/%s%d"%(dir, dir_prefix, random.randint(range_bottom,range_top))
849     
850 #------------------------------------------------------------------#
851 #                                                                  #
852 #                    EXECUTION STARTS HERE                         #
853 #                                                                  #
854 #------------------------------------------------------------------#
855     
856 if __name__ == "__main__":
857     # get program dir
858     cur_dir = get_program_path()
859     # parse command line
860     [xml_file, target_dir, tmp_dir, is_gui] = parse_parameters()
861
862     # define xml file to be used
863     if (xml_file is None):
864         plt_name = ""
865         plt_ver  = ""
866         plt_bit  = ""
867         xml_file_name = "config.xml"
868         if os.path.exists("/etc/redhat-release"):
869             # - Red Hat Linux 8.0
870             # - Red Hat Linux 9
871             # - Mandrake Linux 10.1
872             # - Scientific Linux 3.0.5
873             # - Mandriva 2006.0 32bit/64bit
874             data = open("/etc/redhat-release").readline()
875             res = re.search(r'(.*)[L|l]inux.*release\s+([\d.]*)', data)
876             if res:
877                 plt_name = "".join(res.group(1).split())
878                 plt_ver  = res.group(2)
879                 if re.search(r'x86_64', data):
880                     plt_bit  = "_64"
881         elif os.path.exists("/etc/debian_version"):
882             # - Debian 3.1
883             plt_name = "Debian"
884             plt_ver = open("/etc/debian_version").readline().strip()
885         elif os.path.exists("/etc/mandriva-release"):
886             # - Mandriva 2006 (an additional check if above check fails)
887             data = open("/etc/mandriva-release").readline()
888             res = re.search(r'(.*)[L|l]inux.*release\s+([\d.]*)', data)
889             if res:
890                 plt_name = "".join(res.group(1).split())
891                 plt_ver  = res.group(2)
892                 if re.search(r'x86_64', data):
893                     plt_bit  = "_64"
894                 pass
895         _xml_file_name = "config_%s_%s%s.xml"%(plt_name, plt_ver, plt_bit)
896         if plt_name and plt_ver and os.path.exists("%s/%s"%(cur_dir, _xml_file_name)):
897             xml_file_name = _xml_file_name
898         else:
899             msg  = "Not supported Linux platform!\n"
900             msg += "Trying to use default configuration file!"
901             warning(msg)
902
903         xml_file = "%s/%s"%(cur_dir, xml_file_name)
904
905     if not xml_file or not os.path.exists(xml_file):
906         msg = "Configuration file %s is not found!"%xml_file
907         error_exit(msg)
908
909     if not os.access(xml_file, os.R_OK):
910         msg = "There is no read access for %s file!"%xml_file
911         error_exit(msg)
912
913     #---- GUI ----------------
914
915     if is_gui : 
916         env = os.environ
917         if not env.has_key("PATH") :
918             env["PATH"] = ""
919         if not env.has_key("LD_LIBRARY_PATH") :
920             env["LD_LIBRARY_PATH"] = ""
921
922         env["LD_LIBRARY_PATH"] =  ".:" + env["LD_LIBRARY_PATH"]
923         env["PATH"] = ".:" + env["PATH"]
924
925         cmd = "./bin/SALOME_InstallWizard --file %s"%xml_file
926         if target_dir is not None:
927             cmd += " --target %s"%target_dir
928         if tmp_dir is not None:
929             cmd += " --tmp %s"%tmp_dir
930         cmd += "&"
931         sys.exit(os.system(cmd))
932
933     #-----  TUI ---------------------
934
935     # parse XML file -----------
936     message("Parsing XML configuration file: %s"%xml_file)
937     filehandle = open(xml_file)
938     data = filehandle.read()
939     filehandle.close()
940     parser = ConfigParser()
941     parser.feed(data)
942     parser.close()
943
944     # actions map
945     what_to_do = { __TAG__SOURCES__    : "install_source",
946                    __TAG__BINARIES__   : "install_binary",
947                    __TAG__NATIVE__     : "try_native",
948                    __TAG__PREINSTALL__ : "try_preinstalled"}
949     # source directory map
950     bin_dir = ""
951     if parser.config.os:
952         bin_dir += "/%s"%parser.config.os
953     subdir = { __TAG__SOURCES__    : "SOURCES",
954                __TAG__BINARIES__   : "BINARIES" + bin_dir,
955                __TAG__NATIVE__     : "",
956                __TAG__PREINSTALL__ : ""}
957
958     # check scripts directory -----------
959     scripts_dir = "%s/%s"%(cur_dir, "config_files")
960     check_dir(scripts_dir)
961
962     # check products archives directories -----------
963     has_bin = has_binaries(parser.products)
964     has_src = has_sources(parser.products)
965     source_dir = "%s/%s"%(cur_dir, "Products")
966
967     if has_src or has_bin:
968         check_dir(source_dir)
969
970     if has_src:
971         check_dir("%s/%s"%(source_dir,subdir[__TAG__SOURCES__]))
972
973     if has_bin:
974         check_dir("%s/%s"%(source_dir,subdir[__TAG__BINARIES__]))
975
976     # check/create target dir -----------
977     if target_dir is None:
978         target_dir = parser.path.targetdir
979     target_dir = substituteVars(target_dir)
980
981     message("Creating target directory: " + target_dir)
982     create_dir(target_dir, 0755)
983
984     if not os.path.exists(target_dir):
985         error_exit("Invalid target directory: " + target_dir)
986
987     if not os.access(target_dir, os.W_OK) :
988         error_exit("There is no write permissions for the directory: " + target_dir)
989
990     # check/create temporary dir -----------
991     if tmp_dir is None:
992         tmp_dir = parser.path.tmpdir
993     if not tmp_dir:
994         tmp_dir = "/tmp"
995     tmp_dir = substituteVars(tmp_dir)
996     tmp_dir = get_tmp_dir(tmp_dir)
997
998     message("Creating temporary directory: " + tmp_dir)
999     root_path = create_dir(tmp_dir, 0755)
1000    
1001     if not os.path.exists(tmp_dir):
1002         error_exit("Invalid temporary directory: " + tmp_dir)
1003
1004     if not os.access(tmp_dir, os.W_OK) :
1005         error_exit("There is no write permissions for the directory: " + tmp_dir)
1006         
1007     # check available disk space -----------
1008     message("Checking available disk space")
1009     check_disk_space(parser.products, scripts_dir, target_dir, tmp_dir)
1010
1011     # change current directory -----------
1012     os.chdir(scripts_dir)
1013
1014     # get dependencies list -----------
1015     list_of_dep = get_dependencies(parser.products)
1016
1017     # starting -----------
1018     message("Starting ...")
1019     
1020     # install products -----------
1021     for product in parser.products:
1022         message("... processing %s ..."%product.name)
1023         cmd = '%s/%s %s %s %s/%s %s "%s" %s'%(scripts_dir,
1024                                               product.script,
1025                                               what_to_do[product.install],
1026                                               tmp_dir,
1027                                               source_dir,
1028                                               subdir[product.install],
1029                                               target_dir,
1030                                               list_of_dep,
1031                                               product.name)
1032         res = os.system(cmd)
1033
1034     # pickup environment -----------
1035     message("Creating environment files")
1036     for product in parser.products :
1037         if check_bool(product.pickupEnv):
1038             cmd = '%s/%s pickup_env %s %s/%s %s "%s" %s'%(scripts_dir,
1039                                                           product.script,
1040                                                           tmp_dir,
1041                                                           source_dir,
1042                                                           subdir[product.install],
1043                                                           target_dir,
1044                                                           list_of_dep,
1045                                                           product.name)
1046             res = os.system(cmd)
1047
1048     # clean temporary directory -----------
1049     message("Cleaning temporary directory")
1050     clean_all()
1051     
1052     # finishing -----------
1053     message("Finished!")
1054     pass