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