]> SALOME platform Git repositories - tools/yacsgen.git/blob - module_generator/gener.py
Salome HOME
CCAR: split file __init__.py into several files : templates + implementation specific
[tools/yacsgen.git] / module_generator / gener.py
1 import os, shutil, glob, socket
2
3 try:
4   from string import Template
5 except:
6   from compat import Template, set
7
8 class Invalid(Exception):
9   pass
10
11 from mod_tmpl import resMakefile, makecommon, configure
12 from mod_tmpl import mainMakefile, autogen, application
13 from cata_tmpl import catalog, interface, idl, idlMakefile
14 from cata_tmpl import cataOutStream, cataInStream, cataOutparam, cataInparam
15 from cata_tmpl import cataService, cataCompo
16 from aster_tmpl import check_aster
17
18 corbaTypes = {"double":"CORBA::Double", "long":"CORBA::Long",
19               "string":"const char*", "dblevec":"const %s::dblevec&",
20               "stringvec":"const %s::stringvec&", "intvec":"const %s::intvec&"}
21 corbaOutTypes = {"double":"CORBA::Double&", "long":"CORBA::Long&",
22                 "string":"CORBA::String_out", "dblevec":"%s::dblevec_out",
23                 "stringvec":"%s::stringvec_out", "intvec":"%s::intvec_out"}
24
25 def corba_in_type(typ, module):
26   if typ in ("dblevec", "intvec", "stringvec"):
27     return corbaTypes[typ] % module
28   else:
29     return corbaTypes[typ]
30
31 def corba_out_type(typ, module):
32   if typ in ("dblevec", "intvec", "stringvec"):
33     return corbaOutTypes[typ] % module
34   else:
35     return corbaOutTypes[typ]
36
37 calciumTypes = {"CALCIUM_double":"CALCIUM_double", 
38                 "CALCIUM_integer":"CALCIUM_integer", 
39                 "CALCIUM_real":"CALCIUM_real",
40                 "CALCIUM_string":"CALCIUM_string", 
41                 "CALCIUM_complex":"CALCIUM_complex", 
42                 "CALCIUM_logical":"CALCIUM_logical",
43                } 
44
45 ValidImpl = ("CPP", "PY", "F77", "ASTER")
46 ValidTypes = corbaTypes.keys()
47 ValidStreamTypes = calciumTypes.keys()
48 ValidDependencies = ("I", "T")
49 PyValidTypes = ValidTypes+["pyobj"]
50
51 def makedirs(namedir):
52   if os.path.exists(namedir):
53     dirbak = namedir+".bak"
54     if os.path.exists(dirbak):
55       shutil.rmtree(dirbak)
56     os.rename(namedir, dirbak)
57     os.listdir(dirbak) #sert seulement a mettre a jour le systeme de fichier sur certaines machines
58   os.makedirs(namedir)
59
60 class Module(object):
61   def __init__(self, name, components=None, prefix=""):
62     self.name = name
63     self.components = components or []
64     self.prefix = prefix or "%s_INSTALL" % name
65     self.validate()
66
67   def validate(self):
68     lcompo = set()
69     for compo in self.components:
70       if compo.name in lcompo:
71         raise Invalid("%s is already defined as a component of the module" % compo.name)
72       lcompo.add(compo.name)
73
74 class Component(object):
75   def __init__(self, name, services=None, impl="PY", libs="", rlibs="", 
76                      includes="", kind="lib"):
77     self.name = name
78     self.impl = impl
79     self.kind = kind
80     self.services = services or []
81     self.libs = libs
82     self.rlibs = rlibs
83     self.includes = includes
84     self.validate()
85
86   def validate(self):
87     if self.impl not in ValidImpl:
88       raise Invalid("%s is not a valid implementation. It should be one of %s" % (self.impl, ValidImpl))
89
90     lnames = set()
91     for serv in self.services:
92       serv.impl = self.impl
93       if serv.name in lnames:
94         raise Invalid("%s is already defined as a service of the module" % serv.name)
95       lnames.add(serv.name)
96       serv.validate()
97
98   def getImpl(self):
99     return "SO", ""
100
101 class Service(object):
102   def __init__(self, name, inport=None, outport=None, instream=None, 
103                      outstream=None, body="", defs=""):
104     self.name = name
105     self.inport = inport or []
106     self.outport = outport or []
107     self.instream = instream or []
108     self.outstream = outstream or []
109     self.defs = defs
110     self.body = body
111     self.impl = ""
112
113   def validate(self):
114     lports = set()
115     for port in self.inport:
116       name, typ = self.validatePort(port)
117       if name in lports:
118         raise Invalid("%s is already defined as a service parameter" % name)
119       lports.add(name)
120
121     for port in self.outport:
122       name, typ = self.validatePort(port)
123       if name in lports:
124         raise Invalid("%s is already defined as a service parameter" % name)
125       lports.add(name)
126
127     lports = set()
128     for port in self.instream:
129       name, typ, dep = self.validateStream(port)
130       if name in lports:
131         raise Invalid("%s is already defined as a stream port" % name)
132       lports.add(name)
133
134     for port in self.outstream:
135       name, typ, dep = self.validateStream(port)
136       if name in lports:
137         raise Invalid("%s is already defined as a stream port" % name)
138       lports.add(name)
139
140   def validatePort(self, port):
141     try:
142       name, typ = port
143     except:
144       raise Invalid("%s is not a valid definition of an data port (name,type)" % (port,))
145
146     if self.impl in ("PY", "ASTER"):
147       validtypes = PyValidTypes
148     else:
149       validtypes = ValidTypes
150
151     if typ not in validtypes:
152       raise Invalid("%s is not a valid type. It should be one of %s" % (typ, validtypes))
153     return name, typ
154
155   def validateStream(self, port):
156     try:
157       name, typ, dep = port
158     except:
159       raise Invalid("%s is not a valid definition of a stream port (name,type,dependency)" % (port,))
160     if typ not in ValidStreamTypes:
161       raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidStreamTypes))
162     if dep not in ValidDependencies:
163       raise Invalid("%s is not a valid dependency. It should be one of %s" % (dep, ValidDependencies))
164     return name, typ, dep
165
166 class Generator(object):
167   def __init__(self, module, context=None):
168     self.module = module
169     self.context = context or {}
170     self.kernel = self.context["kernel"]
171     self.aster = ""
172
173   def generate(self):
174     module = self.module
175     namedir = module.name+"_SRC"
176     force = self.context.get("force")
177     update = self.context.get("update")
178     if os.path.exists(namedir):
179       if force:
180         shutil.rmtree(namedir)
181       elif not update:
182         raise Invalid("The directory %s already exists" % namedir)
183     if update:
184       makedirs(namedir)
185     else:
186       os.makedirs(namedir)
187
188     srcs = {}
189     makefile = "SUBDIRS="
190     makefiles = []
191     for compo in module.components:
192       makefile = makefile+" "+compo.name
193       srcs[compo.name] = compo.makeCompo(self)
194       makefiles.append("     src/"+compo.name+"/Makefile")
195
196     srcs["Makefile.am"] = makefile+'\n'
197     idlfile = "%s.idl" % module.name
198     catalogfile = "%sCatalog.xml" % module.name
199
200     self.makeFiles({"autogen.sh":autogen,
201                     "Makefile.am":mainMakefile,
202                     "README":"", "NEWS":"", "AUTHORS":"", "ChangeLog":"",
203                     "configure.ac":configure.substitute(module=module.name.lower(), makefiles='\n'.join(makefiles)),
204                     "idl":{"Makefile.am":idlMakefile.substitute(module=module.name), idlfile:self.makeidl()},
205                     "src":srcs,
206                     "resources":{"Makefile.am":resMakefile.substitute(module=module.name), catalogfile:self.makeCatalog()},
207                     "adm_local":{"make_common_starter.am":makecommon, "check_aster.m4":check_aster},
208                     }, namedir)
209     os.chmod(os.path.join(namedir, "autogen.sh"), 0777)
210
211     for m4file in ("check_Kernel.m4", "check_omniorb.m4", 
212                    "ac_linker_options.m4", "ac_cxx_option.m4",
213                    "python.m4", "enable_pthreads.m4", "check_f77.m4", 
214                    "acx_pthread.m4", "check_boost.m4"):
215       shutil.copyfile(os.path.join(self.kernel, "salome_adm", "unix", "config_files", m4file), 
216                       os.path.join(namedir, "adm_local", m4file))
217
218     return
219
220   def makeArgs(self, service):
221     params = []
222     for name, typ in service.inport:
223       params.append("%s %s" % (corba_in_type(typ, self.module.name), name))
224     for name, typ in service.outport:
225       params.append("%s %s" % (corba_out_type(typ, self.module.name), name))
226     return ",".join(params)
227
228   def makeCatalog(self):
229     components = []
230     for compo in self.module.components:
231       services = []
232       for serv in compo.services:
233         params = []
234         for name, typ in serv.inport:
235           params.append(cataInparam.substitute(name=name, type=typ))
236         inparams = "\n".join(params)
237         params = []
238         for name, typ in serv.outport:
239           params.append(cataOutparam.substitute(name=name, type=typ))
240         outparams = "\n".join(params)
241         streams = []
242         for name, typ, dep in serv.instream:
243           streams.append(cataInStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
244         for name, typ, dep in serv.outstream:
245           streams.append(cataOutStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
246         datastreams = "\n".join(streams)
247         services.append(cataService.substitute(service=serv.name, author="EDF-RD",
248                                                inparams=inparams, outparams=outparams, datastreams=datastreams))
249       impltype, implname = compo.getImpl()
250       components.append(cataCompo.substitute(component=compo.name, author="EDF-RD", impltype=impltype, implname=implname,
251                                              services='\n'.join(services)))
252     return catalog.substitute(components='\n'.join(components))
253
254   def makeidl(self):
255     interfaces = []
256     for compo in self.module.components:
257       services = []
258       for serv in compo.services:
259         params = []
260         for name, typ in serv.inport:
261           if compo.impl in ("PY", "ASTER") and typ == "pyobj":
262             typ = "Engines::fileBlock"
263           params.append("in %s %s" % (typ, name))
264         for name, typ in serv.outport:
265           if compo.impl in ("PY", "ASTER") and typ == "pyobj":
266             typ = "Engines::fileBlock"
267           params.append("out %s %s" % (typ, name))
268         service = "    void %s(" % serv.name
269         service = service+",".join(params)+") raises (SALOME::SALOME_Exception);"
270         services.append(service)
271       interfaces.append(interface.substitute(component=compo.name, services="\n".join(services)))
272     return idl.substitute(module=self.module.name, interfaces='\n'.join(interfaces))
273
274   def makeFiles(self, dic, basedir):
275     for name, content in dic.items():
276       filename = os.path.join(basedir, name)
277       if isinstance(content, str):
278         fil =  open(filename, 'w')
279         fil.write(content)
280         fil.close()
281       else:
282         if not os.path.exists(filename):
283           os.makedirs(filename)
284         self.makeFiles(content, filename)
285
286   def bootstrap(self):
287     ier = os.system("cd %s_SRC;sh autogen.sh" % self.module.name)
288     if ier != 0:
289       raise Invalid("bootstrap has ended in error")
290
291   def configure(self):
292     prefix = self.module.prefix
293     if prefix:
294       prefix = os.path.abspath(prefix)
295       cmd = "cd %s_SRC;./configure --with-kernel=%s --with-aster=%s --prefix=%s"
296       ier = os.system(cmd % (self.module.name, self.kernel, self.aster, prefix))
297     else:
298       cmd = "cd %s_SRC;./configure --with-kernel=%s --with-aster=%s"
299       ier = os.system(cmd % (self.module.name, self.kernel, self.aster))
300     if ier != 0:
301       raise Invalid("configure has ended in error")
302
303   def make(self):
304     ier = os.system("cd %s_SRC;make" % self.module.name)
305     if ier != 0:
306       raise Invalid("make has ended in error")
307
308   def install(self):
309     ier = os.system("cd %s_SRC;make install" % self.module.name)
310     if ier != 0:
311       raise Invalid("install has ended in error")
312
313   def make_appli(self, appliname, restrict=None, altmodules=None):
314     makedirs(appliname)
315
316     rootdir, kerdir = os.path.split(self.kernel)
317
318     #collect modules besides KERNEL module with the same suffix if any
319     modules_dict = {}
320     if kerdir[:6] == "KERNEL":
321       suffix = kerdir[6:]
322       for mod in os.listdir(rootdir):
323         if mod[-len(suffix):] == suffix:
324           module = mod[:-len(suffix)]
325           path = os.path.join(rootdir, mod)
326           #try to find catalog files
327           lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*", "*Catalog.xml"))
328           if not lcata:
329             #catalogs have not been found : try the upper level
330             lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*Catalog.xml"))
331           if lcata:
332             #catalogs have been found : add the corresponding entries in the application
333             for cata in lcata:
334               catadir, catafile = os.path.split(cata)
335               name = catafile[:-11]
336               modules_dict[name] = '  <module name="%s" path="%s"/>' % (name, path)
337           else:
338             modules_dict[module] = '  <module name="%s" path="%s"/>' % (module, path)
339
340     modules_dict["KERNEL"] = '  <module name="KERNEL" path="%s"/>' % self.kernel
341
342     #keep only the modules which names are in restrict if given
343     modules = []
344     if restrict:
345       for mod in restrict:
346         if modules_dict.has_key(mod):
347           modules.append(modules_dict[mod])
348     else:
349       modules = modules_dict.values()
350
351     #add the alternate modules if given
352     if altmodules:
353       for module, path in altmodules.items():
354         modules.append('  <module name="%s" path="%s"/>' % (module, path))
355
356     #add the generated module
357     modules.append('  <module name="%s" path="%s"/>' % (self.module.name, os.path.abspath(self.module.prefix)))
358
359     #try to find a prerequisites file
360     prerequisites = self.context.get("prerequisites")
361     if not prerequisites:
362       #try to find one in rootdir
363       prerequisites = os.path.join(rootdir, "profile%s.sh" % suffix)
364     if not os.path.exists(prerequisites):
365       raise Invalid("Can not create an application : prerequisites file not defined or does not exist")
366
367     #create config_appli.xml file
368     appli = application.substitute(prerequisites=prerequisites, modules="\n".join(modules))
369     fil = open(os.path.join(appliname, "config_appli.xml"), 'w')
370     fil.write(appli)
371     fil.close()
372
373     #execute appli_gen.py script
374     appligen = os.path.join(self.kernel, "bin", "salome", "appli_gen.py")
375     ier = os.system("cd %s;%s" % (appliname, appligen))
376     if ier != 0:
377       raise Invalid("make_appli has ended in error")
378
379     #add CatalogResources.xml if not created by appli_gen.py
380     if not os.path.exists(os.path.join(appliname, "CatalogResources.xml")):
381       #CatalogResources.xml does not exist create a minimal one
382       fil  = open(os.path.join(appliname, 'CatalogResources.xml'), 'w')
383       command = """<!DOCTYPE ResourcesCatalog>
384 <resources>
385     <machine hostname="%s" protocol="ssh" mode="interactive" />
386 </resources>
387 """
388       host = socket.gethostname().split('.')[0]
389       fil.write(command % host)
390       fil.close()
391