Salome HOME
Add COPYING license file
[tools/eficas.git] / Editeur / session.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2021   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 : -l, -j, -p, -d, -i, -f comme definies ci-dessous.
25
26 Un exemple typique d'utilisation est :
27 >>> ./appli.py -v 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 checkComm(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 checkPoursuite(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 checkInclude(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 checkJdc(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=checkJdc(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 checkFich(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     # Python 2 to 3
202     try :
203         import ConfigParser
204         config=ConfigParser.ConfigParser()
205     except :
206         import configparser
207         config=configparser.configparser()
208     config.read([fich])
209     if not config.has_option(u"jdc","jdc"):
210         raise OptionValueError(tr(" jdc %s manque option jdc dans section jdc", str(fich)))
211     jdc=config.get(u"jdc","jdc")
212
213     if not config.has_option(jdc,"comm"):
214         raise OptionValueError(tr(" jdc %(v_1)s manque fichier comm \
215                                  dans section %(v_2)s", {'v_1': fich, 'v_2': jdc}))
216     comm=config.get(jdc,"comm")
217     if not os.path.isfile(comm):
218         raise OptionValueError(tr("jdc %(v_1)s, le fichier de commandes \
219                                  %(v_2)s n'existe pas", {'v_1': fich, 'v_2': comm}))
220     parser.values.comm.append(comm)
221
222     d_study=checkJdc(config,jdc,parser,fich)
223     d_study["comm"]=comm
224     parser.values.studies.append(d_study)
225
226 def printPours(d_pours,dec=''):
227     # Les fichiers includes d'abord
228     for k,v in list(d_pours.items()):
229         if k in (u"pours","comm"):continue
230         print(( tr("%(v_1)s include %(v_2)s : %(v_3)s", {'v_1': str(dec), 'v_2': str(k), 'v_3': str(v)})))
231
232     if "pours" in d_pours:
233         # Description de la poursuite
234         print((tr("%(v_1)s fichier poursuite: %(v_2)s", {'v_1': dec, 'v_2': d_pours["pours"]["comm"]})))
235         printPours(d_pours["pours"],dec=dec+"++")
236
237 def printDEnv():
238     if d_env.studies is None:return
239     for study in d_env.studies:
240         print((tr("nom etude : %s", study["comm"])))
241         printPours(study,dec="++")
242
243 def createparser():
244     # creation du parser des options de la ligne de commande
245     #import prefs
246     parser=optparse.OptionParser(usage=tr("utilisation : %prog [options]"), version="%prog 9.5")
247
248     parser.add_option(u"-j","--jdc",dest="comm",type='string',
249                     action="callback",callback=checkComm,
250                     help=tr("nom du fichier de commandes"))
251
252     parser.add_option(u"-p","--poursuite", type="string",dest="pours",
253                   action="callback", callback=checkPoursuite,
254                   help=tr("nom du fichier poursuite"))
255
256     parser.add_option(u"-i","--include",
257                   action="callback", callback=checkInclude,
258                   nargs=2, help=tr("numero d'unite suivi du nom du fichier include"))
259
260     #parser.add_option(u"-f","--fich", type="string",dest="fich",
261     #              action="callback", callback=checkFich,
262     #              help=tr("fichier decrivant une etude"))
263
264     parser.add_option(u"-c","--cata", action="store", type="string",dest="fichierCata",
265                   help=tr("catalogue a utiliser"))
266
267     parser.add_option(u"-o","--fichierXMLOut", action="store", type="string",dest="fichierXMLOut",
268                   help=tr("nom du fichier xml genere"))
269
270     parser.add_option(u"-v","--label", action="store", type="string",dest="labelCode",
271                   help=tr("version de catalogue a utiliser"))
272
273
274     parser.add_option(u"-k","--kode", action="store", type="string",dest="code",
275                   help=tr("nom du code a utiliser"))
276
277     parser.add_option(u"-d","--debug", action="store", type="int",dest="debug",
278                   help=tr("niveau de debug"))
279
280     parser.add_option(u"-x","--withXSD", action="store_true", dest="withXSD",
281                   default=False,
282                   help=tr("construit le .xml en meme temps que le .comm"))
283
284     parser.add_option(u"-a","--withEltAbstrait", action="store_true", dest="avecEltAbstrait",
285                   default=False,
286                   help=tr("construit des elements abstraits dans le XSD pour gerer le cascading"))
287
288     parser.add_option(u"-s","--schema", action="store", type="string",dest="ssCode",
289                   help=tr("schema"))
290     # To handle locale information
291     #parser.add_option("-l", "--locale", action="store", type="string", dest="locale",
292     #              help=tr("localisation de l'application, pour la traduction"))
293
294
295     return parser
296
297 def parse(args):
298     parser=createparser()
299     (options,args)=parser.parse_args(args[1:])
300     if not hasattr(options,"studies"):
301         options.studies=[]
302         options.comm=[]
303     if not hasattr(options,"fichierCata"): options.fichierCata=None
304     if not hasattr(options,"labelCode"): options.labelCode=None
305     if not hasattr(options,"fichierXMLOut"): options.fichierXMLOut=None
306     if options.withXSD :
307         try : import pyxb
308         except : print ('Please, source pyxb environment'); exit()
309     try:
310         del parser.values.current
311     except:
312         pass
313     for file in args:
314         if os.path.isfile(file):
315             options.comm.append(file)
316             options.studies.append({"comm":file})
317             #print options.studies
318         elif len(args)==1 and (re.search('.comm',file) or re.search('.map',file) or re.search('.cas',file) or re.search('.xml',file)):
319             try :
320                 f=open(file,'w')
321                 f.close()
322             except :
323                 parser.error(tr("Nombre incorrect d'arguments"))
324             options.comm.append(file)
325             options.studies.append({"comm":file})
326         elif len(args) == 2 :
327             if options.locale:
328                 print((tr("Localisation specifiee pour l'application.")))
329             else:
330                 parser.error(tr("Nombre incorrect d'arguments"))
331         else:
332             parser.error(tr("Nombre incorrect d'arguments"))
333
334     global d_env
335     d_env=options
336     #printDEnv()
337     #print (options)
338     return options
339
340 def getUnit(d_study,appliEficas):
341     """
342        Fonction : construit et retourne un dictionnaire contenant les informations
343        sur les fichiers poursuite et includes sous la forme adaptee
344        pour EFICAS ::
345
346                   [None : nom_fichier, texte_source, unites_associees,           # poursuite
347                    numero_include : nom_fichier, texte_source, unites_associees, # include
348                     ...]
349
350        d_study : dictionnaire de l'etude
351        appliEficas : objet application EFICAS (permet d'acceder aux services comme getSource)
352     """
353     return getDunit(d_study,appliEficas)
354
355 def getDunit(d_unit,appliEficas):
356     d={}
357     if 'pours' in d_unit:
358         # on a une poursuite
359         comm=d_unit["pours"]["comm"]
360         g=getDunit(d_unit["pours"],appliEficas)
361         text=appliEficas.getSource(comm)
362         d[None]=comm,text,g
363
364     for k,v in list(d_unit.items()):
365         if k in (u"pours","comm"): continue
366         text=appliEficas.getSource(v)
367         d[k]=v,text,d
368
369     return d