Salome HOME
Updated copyright comment
[modules/kernel.git] / bin / appliskel / update_catalogs.py
1 #!/usr/bin/env python3
2 #  -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 #
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24
25 """
26 """
27 import sys,os,shutil,glob,socket
28 import argparse
29 from salome_utils import getUserName
30
31 import getAppliPath
32 appli_local=os.path.realpath(os.path.dirname(__file__))
33 APPLI=getAppliPath.relpath(appli_local,os.path.realpath(os.path.expanduser("~")))
34
35 usage="""%(prog)s [options]
36 Typical use is:
37   python update_catalogs.py
38
39 You need to have a well installed SALOME application with a CatalogResources.base.xml file.
40 This file is used (parsed) to collect all module catalogs from distant resources and
41 put them in the directory "remote_catalogs" with sub-directories with same name as the distant resource.
42 Distant resources are all the resources except the main SALOME application.
43 Module catalogs from distant resources are copied by the remote protocol declared in the catalog (rcp or rsh)
44 except for the user resources on the local machine (local copy: cp).
45
46 In a second time, this procedure generates a ready to use CatalogResources.xml with all available components
47 for each resource.
48 """
49
50 try:
51   # cElementTree from Python 2.5+
52   import xml.etree.cElementTree as etree_
53 except ImportError:
54   try:
55     import xml.etree.ElementTree as etree_
56   except ImportError:
57     try:
58       import cElementTree as etree_
59     except ImportError:
60       try:
61         # normal ElementTree install
62         import elementtree.ElementTree as etree_
63       except ImportError:
64         raise
65
66 class ParseError(Exception):
67   pass
68
69 catalog_file_base=os.path.join(appli_local,"CatalogResources.base.xml")
70 catalog_file=os.path.join(appli_local,"CatalogResources.xml")
71
72 cata_dir=os.path.join(appli_local,"remote_catalogs")
73 cata_dir_bak=os.path.join(appli_local,"remote_catalogs.bak")
74
75 SEP=":"
76 if sys.platform == "win32":SEP=";"
77
78 def get_hostname():
79   return socket.gethostname().split('.')[0]
80
81 class Component:
82   """Define a SALOME component
83       - name : component name
84       - moduleName : module name
85   """
86   def __init__(self,name,moduleName):
87     self.name=name
88     self.moduleName=moduleName
89
90 class Resource:
91   """Define a SALOME resource
92      - components : the list of available components of the resource
93   """
94   def __init__(self,node):
95     self.node=node
96     self.components=[]
97     self.resource_dir=None
98     self.build()
99
100   def build(self):
101     self.attrs=self.node.attrib
102     #remove all children (components and modules)
103     for child in list(self.node):
104       self.node.remove(child)
105
106   def update(self):
107     for compo in self.components:
108       child=etree_.Element("component",name=compo.name,moduleName=compo.moduleName)
109       child.tail="\n"
110       self.node.append(child)
111
112   def get_rcp(self):
113     protocol= self.node.get("protocol")
114     if protocol and protocol[0]=='s':return "scp"
115     else:return "rcp"
116
117   def get_user(self):
118     userName= self.node.get("userName")
119     if not userName:
120       userName=getUserName()
121     return userName
122
123   def get_host(self):
124     hostname= self.node.get("hostname")
125     return hostname
126
127   def get_name(self):
128     name= self.node.get("name")
129     if name:return name
130     return self.get_host()
131
132   def get_appliPath(self):
133     appliPath= self.node.get("appliPath")
134     if appliPath is None:
135       appliPath=APPLI
136     return appliPath
137
138   def get_catalogs(self):
139     """Get module catalogs file from the resource and copy them locally in remote_catalogs/<resource name>"""
140     hostname=self.get_host()
141     appliPath= self.get_appliPath()
142     userName = self.get_user()
143     rcopy=self.get_rcp()
144
145     resource_dir=os.path.join(cata_dir,self.get_name())
146
147     if hostname == "localhost" or hostname == get_hostname() and userName == getUserName():
148       #local machine, use cp
149       if appliPath[0]!='/':
150         #relative path
151         appliPath=os.path.join(os.path.expanduser("~"),appliPath)
152
153       if appliPath == appli_local:
154         return
155       os.mkdir(resource_dir)
156       cata_path=os.path.join(appliPath,"share","salome","resources","*Catalog.xml")
157       cmd="cp %s %s" % (cata_path,resource_dir)
158       print(cmd)
159       os.system(cmd)
160       cata_path=os.path.join(appliPath,"share","salome","resources","*","*Catalog.xml")
161       cmd="cp %s %s" % (cata_path,resource_dir)
162       print(cmd)
163       os.system(cmd)
164     else:
165       #remote machine, use rcopy
166       os.mkdir(resource_dir)
167       cata_path=os.path.join(appliPath,"share","salome","resources","*Catalog.xml")
168       cmd="%s %s@%s:%s %s"
169       cmd= cmd%(rcopy,userName,hostname,cata_path,resource_dir)
170       print(cmd)
171       os.system(cmd)
172       cata_path=os.path.join(appliPath,"share","salome","resources","*","*Catalog.xml")
173       cmd="%s %s@%s:%s %s"
174       cmd= cmd%(rcopy,userName,hostname,cata_path,resource_dir)
175       print(cmd)
176       os.system(cmd)
177
178     schema_cata=os.path.join(resource_dir,"*SchemaCatalog.xml")
179     os.system("rm %s"% schema_cata)
180
181     self.resource_dir=os.path.abspath(resource_dir)
182
183   def get_components(self):
184     """Retrieve all components declared in module catalogs of the resource"""
185     appliPath= self.get_appliPath()
186     userName = self.get_user()
187     hostname=self.get_host()
188     resource_dir=os.path.join(cata_dir,self.get_name())
189     catalogs_list=glob.glob(os.path.join(resource_dir,"*Catalog.xml"))
190
191     if hostname == "localhost" or hostname == get_hostname() and userName == getUserName():
192       #user local resource
193       if appliPath[0]!='/':
194         appliPath=os.path.join(os.path.expanduser("~"),appliPath)
195       if appliPath == appli_local:
196         #main local resource: get catalogs in share/salome/resources
197         catalogs_list=glob.glob(os.path.join(appliPath,"share","salome","resources","*","*Catalog.xml"))
198         catalogs_list=catalogs_list + glob.glob(os.path.join(appliPath,"share","salome","resources","*Catalog.xml"))
199
200     for cata in catalogs_list:
201       moduleName= os.path.basename(cata)[:-11]
202       #Parse module catalog
203       doc = etree_.parse(cata)
204       rootNode = doc.getroot()
205       for componentName in rootNode.findall("component-list/component/component-name"):
206         self.components.append(Component(componentName.text,moduleName))
207
208
209 def main():
210   parser = argparse.ArgumentParser(usage=usage)
211   args = parser.parse_args()
212
213   if not os.path.exists(catalog_file_base):
214     print("ERROR: the base catalog file %s is mandatory" % catalog_file_base)
215     sys.exit(1)
216
217   #Parse CatalogResource.xml
218   doc = etree_.parse(catalog_file_base)
219
220   rootNode = doc.getroot()
221   if rootNode.tag != "resources":
222     raise  ParseError("First level tag must be resources not %s" % rootNode.tag)
223
224   resources=[]
225
226   #Extract resources
227   for child in rootNode:
228     if child.tag != "machine":
229       raise  ParseError("Second level tag must be machine not %s" % child.tag)
230     resources.append(Resource(child))
231
232   # Remove remote_catalogs directory and create a new empty one
233   if os.path.exists(cata_dir):
234     if os.path.exists(cata_dir_bak):
235       shutil.rmtree(cata_dir_bak)
236     os.rename(cata_dir,cata_dir_bak)
237
238   os.mkdir(cata_dir)
239
240   #Get catalogs from remote resources and copy them in remote_catalogs
241   for mach in resources:
242     mach.get_catalogs()
243
244   #Get the list of SALOME components that are defined in catalogs
245   for mach in resources:
246     mach.get_components()
247
248   #Update the resource catalog dom object for further dump
249   for mach in resources:
250     mach.update()
251
252   #dump new CatalogResources.xml
253   with open(catalog_file,'w') as f:
254       f.write('<?xml version="1.0" ?>\n')
255       doc.write(f)
256       f.write('\n')
257   print("%s updated" % catalog_file)
258
259   #update configRemote.sh in env.d directory (environment variable SALOME_CATALOGS_PATH)
260   path=[]
261   for mach in resources:
262     if mach.resource_dir:
263       path.append(mach.resource_dir)
264
265   with open(os.path.join(appli_local,"env.d","configRemote.sh"),'w') as f:
266       f.write("export SALOME_CATALOGS_PATH=%s\n" % SEP.join(path))
267
268
269 if __name__ == '__main__':
270   main()
271