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