1 #@ MODIF N_JDC Noyau DATE 23/10/2002 AUTEUR DURAND C.DURAND
2 # CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002 EDF R&D WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 # 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
20 # ======================================================================
22 Ce module contient la classe JDC qui sert à interpréter un jeu de commandes
26 import os,string,traceback
27 import types,sys,linecache
32 from N_Exception import AsException
33 from N_ASSD import ASSD
35 class JDC(N_OBJECT.OBJECT):
37 Cette classe interprete un jeu de commandes fourni sous
38 la forme d'une chaine de caractères
42 Attributs d'instance :
54 from N_utils import SEP
56 def __init__(self,definition=None,procedure=None,cata=None,
57 cata_ord_dico=None,parent=None,
58 nom='SansNom',appli=None,context_ini=None,**args):
59 self.procedure=procedure
60 self.definition = definition
62 if type(self.cata) != types.TupleType and cata != None:
63 self.cata=(self.cata,)
64 self.cata_ordonne_dico=cata_ord_dico
68 self.context_ini=context_ini
69 # On conserve les arguments supplémentaires. Il est possible de passer
70 # des informations globales au JDC par ce moyen. Il pourrait etre plus
71 # sur de mettre en place le mecanisme des mots-cles pour verifier la
72 # validité des valeurs passées.
74 # On initialise avec les parametres de la definition puis on
75 # update avec ceux du JDC
76 self.args=self.definition.args
77 self.args.update(args)
82 self.regles=definition.regles
83 self.code = definition.code
88 # Creation de l objet compte rendu pour collecte des erreurs
90 self.cr = self.CR(debut = "CR phase d'initialisation",
91 fin = "fin CR phase d'initialisation")
93 # Liste pour stocker tous les concepts produits dans le JDC
95 # Dictionnaire pour stocker tous les concepts du JDC (acces rapide par le nom)
99 self.current_context={}
100 self.condition_context={}
101 self.index_etape_courante=0
105 Cette methode compile la chaine procedure
106 Si des erreurs se produisent, elles sont consignées dans le
110 if self.appli != None :
111 self.appli.affiche_infos('Compilation du fichier de commandes \
113 self.proc_compile=compile(self.procedure,self.nom,'exec')
114 except SyntaxError,e:
115 if CONTEXT.debug : traceback.print_exc()
116 l=traceback.format_exception_only(SyntaxError,e)
117 self.cr.exception("Compilation impossible : "+string.join(l))
120 def exec_compile(self):
122 Cette méthode execute le jeu de commandes compilé dans le contexte
123 self.g_context de l'objet JDC
125 CONTEXT.set_current_step(self)
126 # Le module nommage utilise le module linecache pour accéder
127 # au source des commandes du jeu de commandes.
128 # Dans le cas d'un fichier, on accède au contenu de ce fichier
129 # Dans le cas d'une chaine de caractères il faut accéder
130 # aux commandes qui sont dans la chaine
132 linecache.cache[self.nom]=0,0,string.split(self.procedure,'\n'),self.nom
134 exec self.exec_init in self.g_context
135 for obj_cata in self.cata:
136 if type(obj_cata) == types.ModuleType :
137 init2 = "from "+obj_cata.__name__+" import *"
138 exec init2 in self.g_context
140 # Initialisation du contexte global pour l'évaluation des conditions de BLOC
141 # On utilise une copie de l'initialisation du contexte du jdc
142 self.condition_context=self.g_context.copy()
144 # Si l'attribut context_ini n'est pas vide, on ajoute au contexte global
145 # le contexte initial (--> permet d'évaluer un JDC en récupérant un contexte
146 # d'un autre par exemple)
147 if self.context_ini :
148 self.g_context.update(self.context_ini)
149 # Update du dictionnaire des concepts
150 for sdnom,sd in self.context_ini.items():
151 if isinstance(sd,ASSD):self.sds_dict[sdnom]=sd
153 if self.appli != None :
154 self.appli.affiche_infos('Interprétation du fichier de \
155 commandes en cours ...')
156 # On sauve le contexte pour garder la memoire des constantes
157 # En mode edition (EFICAS) ou lors des verifications le contexte
159 # mais les constantes sont perdues
160 self.const_context=self.g_context
161 exec self.proc_compile in self.g_context
163 CONTEXT.unset_current_step()
164 if self.appli != None : self.appli.affiche_infos('')
167 # Exception utilise pour interrompre un jeu
168 # de commandes avant la fin
169 # Fonctionnement normal, ne doit pas etre considere comme une erreur
170 CONTEXT.unset_current_step()
172 except AsException,e:
173 # une erreur a ete identifiee
175 traceback.print_exc()
176 self.cr.exception(str(e))
177 CONTEXT.unset_current_step()
180 etype, value, tb = sys.exc_info()
181 l= traceback.extract_tb(tb)
182 s= traceback.format_exception_only("Erreur de nom",e)[0][:-1]
183 message = "erreur de syntaxe, %s ligne %d" % (s,l[-1][1])
186 traceback.print_exc()
187 self.cr.exception(message)
188 CONTEXT.unset_current_step()
192 # sys_exc_typ,sys_exc_value,sys_exc_frame = sys_exc.info()
193 # (tuple de 3 éléments)
195 traceback.print_exc()
196 #prbanner("erreur non prevue et non traitee prevenir \
197 # la maintenance "+self.nom)
198 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],
200 self.cr.exception("erreur non prevue et non traitee prevenir la maintenance "+
201 self.nom+'\n'+ string.join(l))
202 CONTEXT.unset_current_step()
204 def register(self,etape):
206 Cette méthode ajoute etape dans la liste des etapes : self.etapes
207 et retourne un numéro d'enregistrement
209 self.etapes.append(etape)
210 return self.g_register(etape)
212 def o_register(self,sd):
214 Retourne un identificateur pour concept
217 nom=sd.idracine + self.SEP + `self.nsd`
220 def g_register(self,etape):
222 Retourne un identificateur pour etape
224 self.nstep=self.nstep+1
225 idetape=etape.idracine + self.SEP + `self.nstep`
228 def create_sdprod(self,etape,nomsd):
230 Intention : Cette methode doit fabriquer le concept produit retourne
231 par l'etape etape et le nommer.
232 Elle est appelée à l'initiative de l'etape
233 pendant le processus de construction de cette etape :
234 methode __call__ de la classe CMD (OPER ou MACRO)
235 Ce travail est réalisé par le contexte supérieur
236 (etape.parent) car dans certains cas, le concept ne doit
237 pas etre fabriqué mais l'etape doit simplement utiliser
238 un concept préexistant.
239 Cas 1 : etape.reuse != None : le concept est réutilisé
240 Cas 2 : l'étape appartient à une macro qui a déclaré un
241 concept de sortie qui doit etre produit par cette
243 Dans le cas du JDC, le deuxième cas ne peut pas se produire.
245 sd= etape.get_sd_prod()
246 if sd != None and etape.reuse == None:
247 # ATTENTION : On ne nomme la SD que dans le cas de non reutilisation
249 self.NommerSdprod(sd,nomsd)
252 def NommerSdprod(self,sd,sdnom,restrict='non'):
254 Nomme la SD apres avoir verifie que le nommage est possible : nom
256 Si le nom est deja utilise, leve une exception
257 Met le concept créé dans le concept global g_context
259 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
260 o=self.sds_dict.get(sdnom,None)
261 if isinstance(o,ASSD):
262 raise AsException("Nom de concept deja defini : %s" % sdnom)
264 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
265 # Ajoute a la creation (appel de reg_sd).
266 self.sds_dict[sdnom]=sd
269 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
270 if restrict == 'non':
271 self.g_context[sdnom]=sd
275 Methode appelee dans l __init__ d un ASSD lors de sa creation
279 return self.o_register(sd)
281 def delete_concept_after_etape(self,etape,sd):
283 Met à jour les étapes du JDC qui sont après etape suite à
284 la disparition du concept sd
286 # Cette methode est définie dans le noyau mais ne sert que pendant
287 # la phase de creation des etapes et des concepts. Il n'y a aucun
288 # traitement particulier à réaliser.
289 # Dans d'autres conditions, il faut surcharger cette méthode
293 N_OBJECT.OBJECT.supprime(self)
294 for etape in self.etapes:
297 def get_file(self,unite=None,fic_origine=''):
299 Retourne le nom du fichier correspondant à un numero d'unité
300 logique (entier) ainsi que le source contenu dans le fichier
303 # Si le JDC est relié à une application maitre, on délègue la recherche
304 file= self.appli.get_file(unite,fic_origine)
308 if os.path.exists("fort."+str(unite)):
309 file= "fort."+str(unite)
311 raise AsException("Impossible de trouver le fichier correspondant \
312 a l unite %s" % unite)
313 if not os.path.exists(file):
314 raise AsException("%s n'est pas un fichier existant" % unite)
316 text=string.replace(fproc.read(),'\r\n','\n')
318 linecache.cache[file]=0,0,string.split(text,'\n'),file
321 def set_par_lot(self,par_lot):
323 Met le mode de traitement a PAR LOT
324 ou a COMMANDE par COMMANDE
325 en fonction de la valeur du mot cle PAR_LOT et
326 du contexte : application maitre ou pas
328 if self.appli == None:
329 # Pas d application maitre
332 # Avec application maitre
335 def accept(self,visitor):
337 Cette methode permet de parcourir l'arborescence des objets
338 en utilisant le pattern VISITEUR
340 visitor.visitJDC(self)
344 Cette methode a pour fonction d'ouvrir un interpreteur
345 pour que l'utilisateur entre des commandes interactivement
347 CONTEXT.set_current_step(self)
349 # Le module nommage utilise le module linecache pour accéder
350 # au source des commandes du jeu de commandes.
351 # Dans le cas d'un fichier, on accède au contenu de ce fichier
352 # Dans le cas de la console interactive, il faut pouvoir accéder
353 # aux commandes qui sont dans le buffer de la console
354 import linecache,code
355 console= code.InteractiveConsole(self.g_context,filename="<console>")
356 linecache.cache["<console>"]=0,0,console.buffer,"<console>"
357 banner="""***********************************************
358 * Interpreteur interactif %s
359 ***********************************************""" % self.code
360 console.interact(banner)
363 CONTEXT.unset_current_step()
365 def get_contexte_avant(self,etape):
367 Retourne le dictionnaire des concepts connus avant etape
368 On tient compte des commandes qui modifient le contexte
369 comme DETRUIRE ou les macros
370 Si etape == None, on retourne le contexte en fin de JDC
372 # L'étape courante pour laquelle le contexte a été calculé est
373 # mémorisée dans self.index_etape_courante
374 # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en
376 # courante pendant le processus de construction des étapes.
377 # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
378 # remettre ce pointeur à 0
380 index_etape=self.etapes.index(etape)
382 index_etape=len(self.etapes)
383 if index_etape >= self.index_etape_courante:
384 # On calcule le contexte en partant du contexte existant
385 d=self.current_context
386 liste_etapes=self.etapes[self.index_etape_courante:index_etape]
388 d=self.current_context={}
389 liste_etapes=self.etapes
391 for e in liste_etapes:
396 self.index_etape_courante=index_etape
399 def get_global_contexte(self):
400 return self.g_context.copy()