Salome HOME
merge avec les devloppts de l ete
[tools/eficas.git] / Editeur / session.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 """
21 Ce module centralise les informations issues de la ligne de commande.
22
23 La ligne de commande est parsee avec l'aide du module python optparse.
24 Les options possibles sont : -c, -j, -p, -d, -i, -f comme definies ci-dessous.
25
26 Un exemple typique d'utilisation est :
27 >>> ./appli.py -c V7.3 -d 1 -j aa -i 11 iii -p ppp -i 22 ii -j bb -f ff
28
29 qui demande a l'application d'ouvrir trois jeux de commandes.
30
31 Le premier (aa) a un include (11,iii) et est la suite du fichier poursuite ppp 
32 qui a lui meme un include (22,ii).
33
34 Le deuxieme bb est un jeu de commandes simple.
35
36 Le troisieme est decrit dans le fichier ff de type .ini
37 qui est parse par le module ConfigParser.
38 Chaque section du fichier decrit un jeu de commandes.
39 Un include est specifie par: numero logique=nom du fichier
40 Une poursuite est specifiee par: poursuite=reference a un jeu de commande 
41 Cette reference correspond a un nom de section decrivant le jeu de commandes.
42 Le jeu de commandes maitre est donne par l'entree globale jdc dans la section jdc.
43
44 Exemple:
45 [jdc]
46 jdc=a
47 [a]
48 comm=aa
49 poursuite=pours
50 11=iii
51 [pours]
52 comm=ppp
53 22=ii
54
55 La session utilisera le catalogue V7.3 en mode debug.
56 """
57
58 from __future__ import absolute_import
59 from __future__ import print_function
60 try :
61   from builtins import str
62 except :
63   pass
64 try:
65    import optparse
66    from optparse import OptionValueError
67 except:
68    from Tools import optparse
69    from Tools.optparse import OptionValueError
70
71 import os,traceback
72 import six.moves.configparser
73 import re
74
75 from Extensions.i18n import tr
76
77 # Les valeurs decodees par optparse sont mises dans un objet dictionnaire-like.
78 # On l'utilise comme environnement de session.
79 d_env={}
80 #
81 # L'attribut "studies" de d_env est une liste dans laquelle on range les etudes de niveau global.
82 # Une etude est stockee dans un dictionnaire.
83 # La cle "comm" du dictionnaire donne le nom du fichier de commandes principal
84 # La cle (optionnelle) "pours" du dictionnaire donne les informations pour une poursuite
85 # La valeur associee a la cle est un dictionnaire qui contient les informations sur
86 # le nom du fichier de commandes de la poursuite (cle "comm"), une eventuelle poursuite
87 # (cle "pours") et les includes (cles entieres associees a des noms de fichier).
88 #
89 #
90 #
91 # Les informations (dictionnaire) associees au fichier de commandes en cours de traitement 
92 # sont stockees dans parser.values.current
93 # En general, il faut utiliser current et pas parser.values.studies car les informations
94 # sont stockees hierarchiquement
95 #
96
97 def check_comm(option, opt_str, value, parser):
98     if not hasattr(parser.values,"studies"):
99        parser.values.studies=[]
100        parser.values.comm=[]
101     if not os.path.isfile(value):
102        raise OptionValueError(tr("le fichier de commandes %s n'existe pas", value))
103     parser.values.comm.append(value)
104     d_study={"comm":value}
105     parser.values.current=d_study
106     parser.values.studies.append(d_study)
107
108 def check_poursuite(option, opt_str, value, parser):
109     if parser.values.comm is None:
110        raise OptionValueError(tr("un fichier de commandes doit etre defini avant une poursuite %s", value))
111     if not os.path.isfile(value):
112        raise OptionValueError(tr("le fichier poursuite %s n'existe pas", value))
113     #current : fichier de commandes en cours de traitement (dictionnaire des infos)
114     comm=parser.values.current
115     d_study={"comm":value}
116     comm["pours"]=d_study
117     parser.values.current=d_study
118
119 def check_include(option, opt_str, value, parser):
120     try:
121        args=[int(parser.rargs[0]),parser.rargs[1]]
122     except:
123        raise OptionValueError(tr("include mal defini %s", parser.rargs[0:2]))
124
125     del parser.rargs[0]
126     del parser.rargs[0]
127
128     if parser.values.comm is None:
129        raise OptionValueError(tr("un fichier de commandes doit etre defini avant un include %s", args))
130     if not os.path.isfile(args[1]):
131        raise OptionValueError(tr("le fichier include %s n'existe pas", args[1]))
132
133     comm=parser.values.current
134     comm[args[0]]=args[1]
135
136
137 def check_jdc(config,jdc,parser,fich):
138     """
139         Fonction : analyse une section de fichier .ini pour en extraire
140         les informations sur les fichiers poursuite et includes
141         definis dans cette section
142
143         parser : objet analyseur de la ligne de commande
144         fich : nom du fichier .ini en cours d'analyse
145         config : objet de la classe ConfigParser permettant de parser le fichier fich
146         jdc : nom de la section du fichier fich a analyser
147     """
148     d_study={}
149
150     for o in config.options(jdc):
151        if o == "poursuite":
152           p=config.get(jdc,"poursuite")
153
154           if not config.has_option(p,"comm"):
155              raise OptionValueError(tr(" jdc %(v_1)s manque \
156                                       fichier comm dans section %(v_2)s", \
157                                       {'v_1': fich, 'v_2': p}))
158           comm=config.get(p,"comm")
159           if not os.path.isfile(comm):
160              raise OptionValueError(tr("jdc %(v_1)s, le fichier\
161                                       de commandes %(v_2)s n'existe pas", \
162                                       {'v_1': fich, 'v_2': comm}))
163
164           pours=check_jdc(config,p,parser,fich)
165           pours["comm"]=comm
166           d_study["pours"]=pours
167           continue
168
169        try:
170           unit=int(o)
171           # si le parametre est un entier, il s'agit d'un include
172           inc=config.get(jdc,o)
173        except EficasException:
174           continue
175        if not os.path.isfile(inc):
176           raise OptionValueError(tr(" jdc %(v_1)s \
177                                    fichier include %(v_2)s, %(v_3)s \
178                                    n'existe pas", \
179                                    {'v_1': fich, 'v_2': unit, 'v_3': inc}))
180        d_study[unit]=inc
181
182     return d_study
183
184 def check_fich(option, opt_str, fich, parser):
185     """
186         Fonction : parse le fichier fich (format .ini)
187         
188         option : option en cours de traitement
189         opt_str : chaine de caracteres utilisee par l'utilisateur
190         fich : nom du fichier .ini donne par l'utilisateur
191         parser : objet parseur des options de la ligne de commande
192     """
193     if not os.path.isfile(fich):
194        raise OptionValueError(tr(" le fichier jdc %s n'existe pas", str(fich)))
195     if parser.values.fich is None:
196        parser.values.fich=[]
197     parser.values.fich.append(fich)
198     if not hasattr(parser.values,"studies"):
199        parser.values.studies=[]
200        parser.values.comm=[]
201     config = six.moves.configparser.ConfigParser()
202     config.read([fich])
203     if not config.has_option(u"jdc","jdc"):
204        raise OptionValueError(tr(" jdc %s manque option jdc dans section jdc", str(fich)))
205     jdc=config.get(u"jdc","jdc")
206
207     if not config.has_option(jdc,"comm"):
208        raise OptionValueError(tr(" jdc %(v_1)s manque fichier comm \
209                                 dans section %(v_2)s", {'v_1': fich, 'v_2': jdc}))
210     comm=config.get(jdc,"comm")
211     if not os.path.isfile(comm):
212        raise OptionValueError(tr("jdc %(v_1)s, le fichier de commandes \
213                                 %(v_2)s n'existe pas", {'v_1': fich, 'v_2': comm}))
214     parser.values.comm.append(comm)
215
216     d_study=check_jdc(config,jdc,parser,fich)
217     d_study["comm"]=comm
218     parser.values.studies.append(d_study)
219
220 def print_pours(d_pours,dec=''):
221     # Les fichiers includes d'abord
222     for k,v in list(d_pours.items()):
223        if k in (u"pours","comm"):continue
224        print(( tr("%(v_1)s include %(v_2)s : %(v_3)s", {'v_1': str(dec), 'v_2': str(k), 'v_3': str(v)})))
225
226     if "pours" in d_pours:
227        # Description de la poursuite
228        print((tr("%(v_1)s fichier poursuite: %(v_2)s", {'v_1': dec, 'v_2': d_pours["pours"]["comm"]})))
229        print_pours(d_pours["pours"],dec=dec+"++")
230
231 def print_d_env():
232     if d_env.studies is None:return
233     for study in d_env.studies:
234        print((tr("nom etude : %s", study["comm"])))
235        print_pours(study,dec="++")
236
237 def create_parser():
238     # creation du parser des options de la ligne de commande
239     #import prefs
240     parser=optparse.OptionParser(usage=tr("utilisation : %prog [options]"), version="%prog 1.13")
241
242     parser.add_option(u"-j","--jdc",dest="comm",type='string',
243                     action="callback",callback=check_comm,
244                     help=tr("nom du fichier de commandes"))
245
246     parser.add_option(u"-p","--poursuite", type="string",dest="pours",
247                   action="callback", callback=check_poursuite,
248                   help=tr("nom du fichier poursuite"))
249
250     parser.add_option(u"-i","--include", 
251                   action="callback", callback=check_include,
252                   nargs=2, help=tr("numero d'unite suivi du nom du fichier include"))
253
254     parser.add_option(u"-f","--fich", type="string",dest="fich",
255                   action="callback", callback=check_fich,
256                   help=tr("fichier decrivant une etude"))
257
258     parser.add_option(u"-c","--cata", action="store", type="string",dest="cata",
259                   help=tr("version de catalogue a utiliser"))
260
261     parser.add_option(u"-k","--kode", action="store", type="string",dest="code",
262                   help=tr("nom du code a utiliser"))
263
264     parser.add_option(u"-d","--debug", action="store", type="int",dest="debug",
265                   help=tr("niveau de debug"))
266
267     parser.add_option(u"-s","--schema", action="store", type="string",dest="ssCode",
268                   help=tr("schema"))
269     # To handle locale information
270     parser.add_option("-l", "--locale", action="store", type="string", dest="locale",
271                   help=tr("localisation de l'application, pour la traduction"))
272
273
274     return parser
275
276 def parse(args):
277     parser=create_parser()
278     (options,args)=parser.parse_args(args[1:])
279     if not hasattr(options,"studies"):
280        options.studies=[]
281        options.comm=[]
282     try:
283        del parser.values.current
284     except:
285        pass
286     for file in args:
287          if os.path.isfile(file):
288             options.comm.append(file)
289             options.studies.append({"comm":file})
290             #print options.studies
291          elif len(args)==1 and (re.search('.comm',file) or re.search('.map',file) or re.search('.cas',file)):
292             try :
293                 f=open(file,'w')
294                 f.close()
295             except :
296                 parser.error(tr("Nombre incorrect d'arguments"))
297             options.comm.append(file)
298             options.studies.append({"comm":file})
299          elif len(args) == 1 and options.locale:
300             print((tr("Localisation specifiee pour l'application.")))
301          else:
302             parser.error(tr("Nombre incorrect d'arguments"))
303
304     global d_env
305     d_env=options
306     #print_d_env()
307     return options
308
309 def get_unit(d_study,appli):
310     """
311        Fonction : construit et retourne un dictionnaire contenant les informations
312        sur les fichiers poursuite et includes sous la forme adaptee
313        pour EFICAS ::
314
315                   [None : nom_fichier, texte_source, unites_associees,           # poursuite
316                    numero_include : nom_fichier, texte_source, unites_associees, # include
317                     ...] 
318
319        d_study : dictionnaire de l'etude
320        appli : objet application EFICAS (permet d'acceder aux services comme get_source)
321     """
322     return get_dunit(d_study,appli)
323
324 def get_dunit(d_unit,appli):
325     d={}
326     if 'pours' in d_unit:
327        # on a une poursuite
328        comm=d_unit["pours"]["comm"]
329        g=get_dunit(d_unit["pours"],appli)
330        text=appli.get_source(comm)
331        d[None]=comm,text,g
332
333     for k,v in list(d_unit.items()):
334        if k in (u"pours","comm"): continue
335        text=appli.get_source(v)
336        d[k]=v,text,d
337
338     return d