Salome HOME
onItem=Deplie
[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 try:
59    import optparse
60    from optparse import OptionValueError
61 except:
62    from Tools import optparse
63    from Tools.optparse import OptionValueError
64
65 import os,traceback
66 import ConfigParser
67 import re
68
69 from Extensions.i18n import tr
70
71 # Les valeurs decodees par optparse sont mises dans un objet dictionnaire-like.
72 # On l'utilise comme environnement de session.
73 d_env={}
74 #
75 # L'attribut "studies" de d_env est une liste dans laquelle on range les etudes de niveau global.
76 # Une etude est stockee dans un dictionnaire.
77 # La cle "comm" du dictionnaire donne le nom du fichier de commandes principal
78 # La cle (optionnelle) "pours" du dictionnaire donne les informations pour une poursuite
79 # La valeur associee a la cle est un dictionnaire qui contient les informations sur
80 # le nom du fichier de commandes de la poursuite (cle "comm"), une eventuelle poursuite
81 # (cle "pours") et les includes (cles entieres associees a des noms de fichier).
82 #
83 #
84 #
85 # Les informations (dictionnaire) associees au fichier de commandes en cours de traitement 
86 # sont stockees dans parser.values.current
87 # En general, il faut utiliser current et pas parser.values.studies car les informations
88 # sont stockees hierarchiquement
89 #
90
91 def check_comm(option, opt_str, value, parser):
92     if not hasattr(parser.values,"studies"):
93        parser.values.studies=[]
94        parser.values.comm=[]
95     if not os.path.isfile(value):
96        raise OptionValueError(tr("le fichier de commandes %s n'existe pas", value))
97     parser.values.comm.append(value)
98     d_study={"comm":value}
99     parser.values.current=d_study
100     parser.values.studies.append(d_study)
101
102 def check_poursuite(option, opt_str, value, parser):
103     if parser.values.comm is None:
104        raise OptionValueError(tr("un fichier de commandes doit etre defini avant une poursuite %s", value))
105     if not os.path.isfile(value):
106        raise OptionValueError(tr("le fichier poursuite %s n'existe pas", value))
107     #current : fichier de commandes en cours de traitement (dictionnaire des infos)
108     comm=parser.values.current
109     d_study={"comm":value}
110     comm["pours"]=d_study
111     parser.values.current=d_study
112
113 def check_include(option, opt_str, value, parser):
114     try:
115        args=[int(parser.rargs[0]),parser.rargs[1]]
116     except:
117        raise OptionValueError(tr("include mal defini %s", parser.rargs[0:2]))
118
119     del parser.rargs[0]
120     del parser.rargs[0]
121
122     if parser.values.comm is None:
123        raise OptionValueError(tr("un fichier de commandes doit etre defini avant un include %s", args))
124     if not os.path.isfile(args[1]):
125        raise OptionValueError(tr("le fichier include %s n'existe pas", args[1]))
126
127     comm=parser.values.current
128     comm[args[0]]=args[1]
129
130
131 def check_jdc(config,jdc,parser,fich):
132     """
133         Fonction : analyse une section de fichier .ini pour en extraire
134         les informations sur les fichiers poursuite et includes
135         definis dans cette section
136
137         parser : objet analyseur de la ligne de commande
138         fich : nom du fichier .ini en cours d'analyse
139         config : objet de la classe ConfigParser permettant de parser le fichier fich
140         jdc : nom de la section du fichier fich à analyser
141     """
142     d_study={}
143
144     for o in config.options(jdc):
145        if o == "poursuite":
146           p=config.get(jdc,"poursuite")
147
148           if not config.has_option(p,"comm"):
149              raise OptionValueError(tr(" jdc %(v_1)s manque \
150                                       fichier comm dans section %(v_2)s", \
151                                       {'v_1': fich, 'v_2': p}))
152           comm=config.get(p,"comm")
153           if not os.path.isfile(comm):
154              raise OptionValueError(tr("jdc %(v_1)s, le fichier\
155                                       de commandes %(v_2)s n'existe pas", \
156                                       {'v_1': fich, 'v_2': comm}))
157
158           pours=check_jdc(config,p,parser,fich)
159           pours["comm"]=comm
160           d_study["pours"]=pours
161           continue
162
163        try:
164           unit=int(o)
165           # si le parametre est un entier, il s'agit d'un include
166           inc=config.get(jdc,o)
167        except EficasException:
168           continue
169        if not os.path.isfile(inc):
170           raise OptionValueError(tr(" jdc %(v_1)s \
171                                    fichier include %(v_2)s, %(v_3)s \
172                                    n'existe pas", \
173                                    {'v_1': fich, 'v_2': unit, 'v_3': inc}))
174        d_study[unit]=inc
175
176     return d_study
177
178 def check_fich(option, opt_str, fich, parser):
179     """
180         Fonction : parse le fichier fich (format .ini)
181         
182         option : option en cours de traitement
183         opt_str : chaine de caracteres utilisee par l'utilisateur
184         fich : nom du fichier .ini donne par l'utilisateur
185         parser : objet parseur des options de la ligne de commande
186     """
187     if not os.path.isfile(fich):
188        raise OptionValueError(tr(" le fichier jdc %s n'existe pas", str(fich)))
189     if parser.values.fich is None:
190        parser.values.fich=[]
191     parser.values.fich.append(fich)
192     if not hasattr(parser.values,"studies"):
193        parser.values.studies=[]
194        parser.values.comm=[]
195     config = ConfigParser.ConfigParser()
196     config.read([fich])
197     if not config.has_option(u"jdc","jdc"):
198        raise OptionValueError(tr(" jdc %s manque option jdc dans section jdc", str(fich)))
199     jdc=config.get(u"jdc","jdc")
200
201     if not config.has_option(jdc,"comm"):
202        raise OptionValueError(tr(" jdc %(v_1)s manque fichier comm \
203                                 dans section %(v_2)s", {'v_1': fich, 'v_2': jdc}))
204     comm=config.get(jdc,"comm")
205     if not os.path.isfile(comm):
206        raise OptionValueError(tr("jdc %(v_1)s, le fichier de commandes \
207                                 %(v_2)s n'existe pas", {'v_1': fich, 'v_2': comm}))
208     parser.values.comm.append(comm)
209
210     d_study=check_jdc(config,jdc,parser,fich)
211     d_study["comm"]=comm
212     parser.values.studies.append(d_study)
213
214 def print_pours(d_pours,dec=''):
215     # Les fichiers includes d'abord
216     for k,v in d_pours.items():
217        if k in (u"pours","comm"):continue
218        print tr("%(v_1)s include %(v_2)s : %(v_3)s", {'v_1': str(dec), 'v_2': str(k), 'v_3': str(v)})
219
220     if d_pours.has_key(u"pours"):
221        # Description de la poursuite
222        print tr("%(v_1)s fichier poursuite: %(v_2)s", {'v_1': dec, 'v_2': d_pours["pours"]["comm"]})
223        print_pours(d_pours["pours"],dec=dec+"++")
224
225 def print_d_env():
226     #print d_env
227     if d_env.studies is None:return
228     for study in d_env.studies:
229        print tr("nom etude : %s", study["comm"])
230        print_pours(study,dec="++")
231        print
232
233 def create_parser():
234     # creation du parser des options de la ligne de commande
235     #import prefs
236     parser=optparse.OptionParser(usage=tr("utilisation : %prog [options]"), version="%prog 1.13")
237
238     parser.add_option(u"-j","--jdc",dest="comm",type='string',
239                     action="callback",callback=check_comm,
240                     help=tr("nom du fichier de commandes"))
241
242     parser.add_option(u"-p","--poursuite", type="string",dest="pours",
243                   action="callback", callback=check_poursuite,
244                   help=tr("nom du fichier poursuite"))
245
246     parser.add_option(u"-i","--include", 
247                   action="callback", callback=check_include,
248                   nargs=2, help=tr("numero d'unite suivi du nom du fichier include"))
249
250     parser.add_option(u"-f","--fich", type="string",dest="fich",
251                   action="callback", callback=check_fich,
252                   help=tr("fichier decrivant une etude"))
253
254     parser.add_option(u"-c","--cata", action="store", type="string",dest="cata",
255                   help=tr("version de catalogue a utiliser"))
256
257     parser.add_option(u"-k","--kode", action="store", type="string",dest="code",
258                   help=tr("nom du code a utiliser"))
259
260     parser.add_option(u"-d","--debug", action="store", type="int",dest="debug",
261                   help=tr("niveau de debug"))
262
263     parser.add_option(u"-s","--schema", action="store", type="string",dest="ssCode",
264                   help=tr("schema"))
265     # To handle locale information
266     parser.add_option("-l", "--locale", action="store", type="string", dest="locale",
267                   help=tr("localisation de l'application, pour la traduction"))
268
269
270     return parser
271
272 def parse(args):
273     parser=create_parser()
274     (options,args)=parser.parse_args(args[1:])
275     if not hasattr(options,"studies"):
276        options.studies=[]
277        options.comm=[]
278     try:
279        del parser.values.current
280     except:
281        pass
282     for file in args:
283          if os.path.isfile(file):
284             options.comm.append(file)
285             options.studies.append({"comm":file})
286             #print options.studies
287          elif len(args)==1 and (re.search('.comm',file) or re.search('.map',file)):
288             try :
289                 f=open(file,'w')
290                 f.close()
291             except :
292                 parser.error(tr("Nombre incorrect d'arguments"))
293             options.comm.append(file)
294             options.studies.append({"comm":file})
295          elif len(args) == 1 and options.locale:
296             print tr("Localisation specifiee pour l'application.")
297          else:
298             parser.error(tr("Nombre incorrect d'arguments"))
299
300     global d_env
301     d_env=options
302     #print_d_env()
303     return options
304
305 def get_unit(d_study,appli):
306     """
307        Fonction : construit et retourne un dictionnaire contenant les informations
308        sur les fichiers poursuite et includes sous la forme adaptee
309        pour EFICAS ::
310
311                   [None : nom_fichier, texte_source, unites_associees,           # poursuite
312                    numero_include : nom_fichier, texte_source, unites_associees, # include
313                     ...] 
314
315        d_study : dictionnaire de l'etude
316        appli : objet application EFICAS (permet d'acceder aux services comme get_source)
317     """
318     return get_dunit(d_study,appli)
319
320 def get_dunit(d_unit,appli):
321     d={}
322     if d_unit.has_key(u"pours"):
323        # on a une poursuite
324        comm=d_unit["pours"]["comm"]
325        g=get_dunit(d_unit["pours"],appli)
326        text=appli.get_source(comm)
327        d[None]=comm,text,g
328
329     for k,v in d_unit.items():
330        if k in (u"pours","comm"): continue
331        text=appli.get_source(v)
332        d[k]=v,text,d
333
334     return d