Salome HOME
8a804547b69236b3631e1f8244944360bdcbfed8
[tools/eficas.git] / Editeur / session.py
1 # -*- coding: iso-8859-15 -*-
2 """
3 Ce module centralise les informations issues de la ligne de commande.
4
5 La ligne de commande est parsee avec l'aide du module python optparse.
6 Les options possibles sont : -c, -j, -p, -d, -i, -f comme definies ci-dessous.
7
8 Un exemple typique d'utilisation est :
9 >>> ./appli.py -c V7.3 -d 1 -j aa -i 11 iii -p ppp -i 22 ii -j bb -f ff
10
11 qui demande a l'application d'ouvrir trois jeux de commandes.
12
13 Le premier (aa) a un include (11,iii) et est la suite du fichier poursuite ppp 
14 qui a lui meme un include (22,ii).
15
16 Le deuxieme bb est un jeu de commandes simple.
17
18 Le troisieme est decrit dans le fichier ff de type .ini
19 qui est parse par le module ConfigParser.
20 Chaque section du fichier decrit un jeu de commandes.
21 Un include est specifie par: numero logique=nom du fichier
22 Une poursuite est specifiee par: poursuite=reference a un jeu de commande 
23 Cette reference correspond a un nom de section decrivant le jeu de commandes.
24 Le jeu de commandes maitre est donne par l'entree globale jdc dans la section jdc.
25
26 Exemple:
27 [jdc]
28 jdc=a
29 [a]
30 comm=aa
31 poursuite=pours
32 11=iii
33 [pours]
34 comm=ppp
35 22=ii
36
37 La session utilisera le catalogue V7.3 en mode debug.
38 """
39
40 import optparse
41 from optparse import OptionValueError
42 import traceback
43 import ConfigParser, os
44
45 # Les valeurs decodees par optparse sont mises dans un objet dictionnaire-like.
46 # On l'utilise comme environnement de session.
47 d_env={}
48 #
49 # L'attribut "studies" de d_env est une liste dans laquelle on range les etudes de niveau global.
50 # Une étude est stockée dans un dictionnaire.
51 # La clé "comm" du dictionnaire donne le nom du fichier de commandes principal
52 # La clé (optionnelle) "pours" du dictionnaire donne les informations pour une poursuite
53 # La valeur associée à la clé est un dictionnaire qui contient les informations sur
54 # le nom du fichier de commandes de la poursuite (clé "comm"), une éventuelle poursuite
55 # (clé "pours") et les includes (clés entières associées à des noms de fichier).
56 #
57 #
58 #
59 # Les informations (dictionnaire) associées au fichier de commandes en cours de traitement 
60 # sont stockées dans parser.values.current
61 # En general, il faut utiliser current et pas parser.values.studies car les informations
62 # sont stockées hiérarchiquement
63 #
64
65 def check_comm(option, opt_str, value, parser):
66     if not hasattr(parser.values,"studies"):
67        parser.values.studies=[]
68        parser.values.comm=[]
69     if not os.path.isfile(value):
70        raise OptionValueError("le fichier de commandes %s n'existe pas" % value)
71     parser.values.comm.append(value)
72     d_study={"comm":value}
73     parser.values.current=d_study
74     parser.values.studies.append(d_study)
75
76 def check_poursuite(option, opt_str, value, parser):
77     if parser.values.comm is None:
78        raise OptionValueError("un fichier de commandes doit etre defini avant une poursuite %s" % value)
79     if not os.path.isfile(value):
80        raise OptionValueError("le fichier poursuite %s n'existe pas" % value)
81     #current : fichier de commandes en cours de traitement (dictionnaire des infos)
82     comm=parser.values.current
83     d_study={"comm":value}
84     comm["pours"]=d_study
85     parser.values.current=d_study
86
87 def check_include(option, opt_str, value, parser):
88     try:
89        args=[int(parser.rargs[0]),parser.rargs[1]]
90     except:
91        raise OptionValueError("include mal defini %s" % parser.rargs[0:2])
92
93     del parser.rargs[0]
94     del parser.rargs[0]
95
96     if parser.values.comm is None:
97        raise OptionValueError("un fichier de commandes doit etre defini avant un include %s" % args)
98     if not os.path.isfile(args[1]):
99        raise OptionValueError("le fichier include %s n'existe pas" % args[1])
100
101     comm=parser.values.current
102     comm[args[0]]=args[1]
103
104
105 def check_jdc(config,jdc,parser,fich):
106     """
107         Fonction : analyse une section de fichier .ini pour en extraire
108                    les informations sur les fichiers poursuite et includes
109                    définis dans cette section
110
111         parser : objet analyseur de la ligne de commande
112         fich : nom du fichier .ini en cours d'analyse
113         config : objet de la classe ConfigParser permettant de parser le fichier fich
114         jdc : nom de la section du fichier fich à analyser
115     """
116     d_study={}
117
118     for o in config.options(jdc):
119        if o == "poursuite":
120           p=config.get(jdc,"poursuite")
121
122           if not config.has_option(p,"comm"):
123              raise OptionValueError("jdc %s manque fichier comm dans section %s" % (fich,p))
124           comm=config.get(p,"comm")
125           if not os.path.isfile(comm):
126              raise OptionValueError("jdc %s, le fichier de commandes %s n'existe pas" % (fich,comm))
127
128           pours=check_jdc(config,p,parser,fich)
129           pours["comm"]=comm
130           d_study["pours"]=pours
131           continue
132
133        try:
134           unit=int(o)
135           # si le parametre est un entier, il s'agit d'un include
136           inc=config.get(jdc,o)
137        except:
138           continue
139        if not os.path.isfile(inc):
140           raise OptionValueError("jdc %s fichier include %s, %s n'existe pas" % (fich,unit,inc))
141        d_study[unit]=inc
142
143     return d_study
144
145 def check_fich(option, opt_str, fich, parser):
146     """
147         Fonction : parse le fichier fich (format .ini)
148         
149         option : option en cours de traitement
150         opt_str : chaine de caracteres utilisee par l'utilisateur
151         fich : nom du fichier .ini donné par l'utilisateur
152         parser : objet parseur des options de la ligne de commande
153     """
154     if not os.path.isfile(fich):
155        raise OptionValueError("le fichier jdc %s n'existe pas" % fich)
156     if parser.values.fich is None:
157        parser.values.fich=[]
158     parser.values.fich.append(fich)
159     if not hasattr(parser.values,"studies"):
160        parser.values.studies=[]
161        parser.values.comm=[]
162     config = ConfigParser.ConfigParser()
163     config.read([fich])
164     if not config.has_option("jdc","jdc"):
165        raise OptionValueError("jdc %s manque option jdc dans section jdc")
166     jdc=config.get("jdc","jdc")
167
168     if not config.has_option(jdc,"comm"):
169        raise OptionValueError("jdc %s manque fichier comm dans section %s" % (fich,jdc))
170     comm=config.get(jdc,"comm")
171     if not os.path.isfile(comm):
172        raise OptionValueError("jdc %s, le fichier de commandes %s n'existe pas" % (fich,comm))
173     parser.values.comm.append(comm)
174
175     d_study=check_jdc(config,jdc,parser,fich)
176     d_study["comm"]=comm
177     parser.values.studies.append(d_study)
178
179 def print_pours(d_pours,dec=''):
180     # Les fichiers includes d'abord
181     for k,v in d_pours.items():
182        if k in ("pours","comm"):continue
183        print dec+" include",k," :",v
184
185     if d_pours.has_key("pours"):
186        # Description de la poursuite
187        print dec+" fichier poursuite:",d_pours["pours"]["comm"]
188        print_pours(d_pours["pours"],dec=dec+"++")
189
190 def print_d_env():
191     #print d_env
192     if d_env.studies is None:return
193     for study in d_env.studies:
194        print "nom etude:",study["comm"]
195        print_pours(study,dec="++")
196        print
197
198 def create_parser():
199     # creation du parser des options de la ligne de commande
200     parser=optparse.OptionParser(usage="usage: %prog [options]",version="%prog 1.8")
201
202     parser.add_option("-j","--jdc",dest="comm",type='string',
203                     action="callback",callback=check_comm,
204                     help="nom du fichier de commandes")
205     parser.add_option("-p","--poursuite", type="string",dest="pours",
206                   action="callback", callback=check_poursuite,
207                   help="nom du fichier poursuite")
208     parser.add_option("-i","--include", 
209                   action="callback", callback=check_include,
210                   nargs=2, help="numero d'unite suivi du nom du fichier include")
211
212     parser.add_option("-f","--fich", type="string",dest="fich",
213                   action="callback", callback=check_fich,
214                   help="fichier decrivant une etude")
215
216     parser.add_option("-c","--cata", action="store", type="string",dest="cata",
217                   help="version de catalogue a utiliser")
218
219     parser.add_option("-d","--debug", action="store", type="int",dest="debug",
220                   help="niveau de debug")
221
222     return parser
223
224 def parse(args):
225     parser=create_parser()
226     (options,args)=parser.parse_args(args)
227     if not hasattr(options,"studies"):
228        options.studies=[]
229        options.comm=[]
230     try:
231        del parser.values.current
232     except:
233        pass
234
235     if len(args) > 1:
236       for file in args[1:]:
237          if os.path.isfile(file):
238             options.comm.append(file)
239             options.studies.append({"comm":file})
240          else:
241             parser.error("incorrect number of arguments")
242
243     global d_env
244     d_env=options
245     #print_d_env()
246     return options
247
248 def get_unit(d_study,appli):
249     """
250        Fonction : construit et retourne un dictionnaire contenant les informations
251                   sur les fichiers poursuite et includes sous la forme adaptée
252                   pour EFICAS
253                   [None : nom_fichier, texte_source, unites_associees,           # poursuite
254                    numero_include : nom_fichier, texte_source, unites_associees, # include
255                     ...] 
256        d_study : dictionnaire de l'etude
257        appli : objet application EFICAS (permet d'acceder aux services comme get_source)
258     """
259     return get_dunit(d_study,appli)
260
261 def get_dunit(d_unit,appli):
262     d={}
263     if d_unit.has_key("pours"):
264        # on a une poursuite
265        comm=d_unit["pours"]["comm"]
266        g=get_dunit(d_unit["pours"],appli)
267        text=appli.get_source(comm)
268        d[None]=comm,text,g
269
270     for k,v in d_unit.items():
271        if k in ("pours","comm"): continue
272        text=appli.get_source(v)
273        d[k]=v,text,d
274
275     return d