Skip to content

Commit c8a81f9

Browse files
committed
Add CEA repo
0 parents  commit c8a81f9

File tree

5 files changed

+448
-0
lines changed

5 files changed

+448
-0
lines changed

LICENSE

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Copyright 2020 CEA Organization.
2+
This opi2bob_recursive_converter module is distributed subject to the following license conditions:
3+
SOFTWARE LICENSE AGREEMENT
4+
Software: opi2bob_recursive_converter
5+
1. The "Software", below, refers to opi2bob_recursive_converter (in either source code, or binary
6+
form and accompanying documentation). Each licensee is addressed as "you" or
7+
"Licensee."
8+
2. The copyright holders shown above and their third-party licensors hereby
9+
grant Licensee a royalty-free nonexclusive license, subject to the
10+
limitations stated herein and French Government license rights.
11+
3. You may modify and make a copy or copies of the Software for use within your
12+
organization, if you meet the following conditions:
13+
a. Copies in source code must include the copyright notice and this
14+
Software License Agreement.
15+
b. Copies in binary form must include the copyright notice and this
16+
Software License Agreement in the documentation and/or other materials
17+
provided with the copy.
18+
4. You may modify a copy or copies of the Software or any portion of it, thus
19+
forming a work based on the Software, and distribute copies of such work
20+
outside your organization, if you meet all of the following conditions:
21+
a. Copies in source code must include the copyright notice and this
22+
Software License Agreement;
23+
b. Copies in binary form must include the copyright notice and this
24+
Software License Agreement in the documentation and/or other materials
25+
provided with the copy;
26+
c. Modified copies and works based on the Software must carry prominent
27+
notices stating that you changed specified portions of the Software.
28+
5. Portions of the Software resulted from work developed under a French
29+
Government contract and are subject to the following license: the Government
30+
is granted for itself and others acting on its behalf a paid-up,
31+
nonexclusive, irrevocable worldwide license in this computer software to
32+
reproduce, prepare derivative works, and perform publicly and display
33+
publicly.
34+
6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF
35+
ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE FRENCH,
36+
THE FRENCH DEPARTMENT OF ENERGY, AND THEIR EMPLOYEES: (1) DISCLAIM ANY
37+
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED
38+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR
39+
NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY OR RESPONSIBILITY
40+
FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF THE SOFTWARE, (3) DO NOT
41+
REPRESENT THAT USE OF THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED
42+
RIGHTS, (4) DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED,
43+
THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED.
44+
7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR THIRD
45+
PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY,
46+
OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, CONSEQUENTIAL,
47+
SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED
48+
TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER SUCH
49+
LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE
50+
OR STRICT LIABILITY), OR OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN
51+
WARNED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGES.

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# CSS - Phoebus converter
2+
3+
This python scripts create the same bob folder architecture (with the same content, such as symbolic links, scripts or other documents) as the opi folder, resize CSS opi windows, convert all CSS opi files to Phoebus bob files, and then update the Phoebus bob files.
4+
5+
6+
!!Prerequisit : the opi files have to be stored in a folder named opi
7+
8+
Usage on Windows :
9+
Phoebus_Installation_Path/python_windows/python Phoebus_Installation_Path/tools/opi2bob_recursive_converter.py opi_folder Phoebus_Installation_Path
10+
ex : D:\Phoebus\phoebus-4.7.2\python_windows\python D:\Phoebus\phoebus-4.7.2\tools\opi2bob_recursive_converter.py D:\EPICS\IOC\opi D:\Phoebus\phoebus-4.7.2\
11+
12+
Usage on linux :
13+
python Phoebus_Installation_Path/tools/opi2bob_recursive_converter.py opi_folder Phoebus_Installation_Path
14+
python /home/user/phoebus-4.7.2/tools/opi2bob_recursive_converter.py /home/epics/ioc/opi /home/user/phoebus-4.7.2
15+

bob_update.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#
2+
# *******************************************************************************
3+
# Copyright (c) 2020 by CEA.
4+
# The full license specifying the redistribution, modification, usage and other rights
5+
# and obligations is included with the distribution of this project in the file "license.txt"
6+
#
7+
# THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT EVEN
8+
#
9+
# THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE
10+
# ASSUMES NO RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING FROM THE USE,
11+
# MODIFICATION, OR REDISTRIBUTION OF THIS SOFTWARE.
12+
# ******************************************************************************
13+
# C.E.A. IRFU/DIS/LDISC
14+
#
15+
#
16+
#Script for recursively converting CSS opi files into Phoebus bob files
17+
#Created on 24 May 2023
18+
#
19+
#author: Antoine Choquet
20+
#email: antoine.choquet@cea.fr
21+
#
22+
#contributor: Lea Perez
23+
24+
import xml.etree.ElementTree as ET
25+
import logging
26+
import os
27+
28+
def bob_updating(bob_file, bob_dirname):
29+
tree = ET.parse(bob_file)
30+
root = tree.getroot()
31+
32+
format = '%(asctime)s - %(levelname)-8s - %(message)s'
33+
logfile = bob_dirname + "/" + "Conversion_opi_to_bob.log"
34+
stream_handler = logging.StreamHandler()
35+
stream_handler.setLevel(logging.DEBUG)
36+
logging.basicConfig(format=format, level=logging.DEBUG, datefmt='%m/%d/%Y %I:%M:%S', force=True, handlers=[logging.FileHandler(logfile, mode='a'), stream_handler])
37+
38+
bob_file_name = os.path.basename(bob_file)
39+
logging.info(f"Updating: {bob_file_name} ")
40+
41+
i = 0
42+
j = 0
43+
k = 0
44+
l = 0
45+
same_bob = ""
46+
47+
#update the link to other Phoebus bob
48+
for file in root.iter('file'):
49+
if file is not None:
50+
opi = str(file.text)
51+
bob = str(opi.replace("opi","bob"))
52+
file.text = bob
53+
if same_bob == bob:
54+
i += 1
55+
same_bob = bob
56+
elif same_bob != "":
57+
if i == 0 or i == 1:
58+
logging.debug(f"the link to the graphical interface: {same_bob} has been updated")
59+
else:
60+
logging.debug(f"the link to the graphical interface: {same_bob} have been updated {i} times")
61+
same_bob = bob
62+
i = 0
63+
else:
64+
i += 1
65+
same_bob = bob
66+
67+
if same_bob != "":
68+
if i == 0 or i == 1:
69+
logging.debug(f"the link to the graphical interface: {same_bob} has been updated")
70+
else:
71+
logging.debug(f"the link to the graphical interface: {same_bob} have been updated {i} times")
72+
73+
#Delete gridLayout widget
74+
for widget in root.iter('widget'):
75+
for gridLayout in widget.findall('widget'):
76+
if gridLayout is not None and gridLayout.get('typeId') == "org.csstudio.opibuilder.widgets.gridLayout":
77+
widget.remove(gridLayout)
78+
i += 1
79+
#update the color property name of polyline widget
80+
if widget.get('type') == "polyline":
81+
for rule in widget.findall('./rules/rule'):
82+
if rule is not None:
83+
rule.set('prop_id', 'line_color')
84+
k += 1
85+
86+
if widget.get('type') == "xyplot":
87+
l += 1
88+
89+
90+
for script in root.iter('script'):
91+
if script is not None:
92+
script = script.get('file')
93+
if "changeMacroValue.js" in script:
94+
logging.warning(f"the script: {script} can be remplaced by a simpler embedded script")
95+
else:
96+
logging.warning(f"the script: {script} may not work")
97+
98+
99+
if j !=0:
100+
logging.debug(f"{i} gridLayout widgets have been removed")
101+
102+
if k !=0:
103+
logging.debug(f"{k} polyline widgets have been updated")
104+
105+
if l !=0:
106+
if l ==1:
107+
logging.warning(f"there is 1 xyplot that might have a different behavior")
108+
else:
109+
logging.warning(f"there are {l} xyplot that might have a different behavior")
110+
111+
tree.write(bob_file, xml_declaration=True, method='xml', encoding='UTF-8')
112+
113+
while True:
114+
try:
115+
tree = ET.parse(bob_file)
116+
break
117+
except Exception:
118+
print("Error:", {bob_file}, "is corrupted")
119+
break

opi2bob_recursive_converter.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#
2+
# *******************************************************************************
3+
# Copyright (c) 2020 by CEA.
4+
# The full license specifying the redistribution, modification, usage and other rights
5+
# and obligations is included with the distribution of this project in the file "license.txt"
6+
#
7+
# THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT EVEN
8+
#
9+
# THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE
10+
# ASSUMES NO RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING FROM THE USE,
11+
# MODIFICATION, OR REDISTRIBUTION OF THIS SOFTWARE.
12+
# ******************************************************************************
13+
# C.E.A. IRFU/DIS/LDISC
14+
#
15+
#
16+
#Script for recursively converting CSS opi files into Phoebus bob files
17+
#Created on 24 May 2023
18+
#
19+
#author: Antoine Choquet
20+
#email: antoine.choquet@cea.fr
21+
#
22+
#contributor: Lea Perez
23+
24+
import argparse
25+
import os
26+
import subprocess
27+
import re
28+
import shutil
29+
import platform
30+
from resize_opi import opi_resizing
31+
from bob_update import bob_updating
32+
33+
def search_dirs(search_string, rootdir):
34+
dirs_list=[]
35+
for rootdir, dirs, files in os.walk(rootdir):
36+
for subdir in dirs:
37+
absolute_path = os.path.join(rootdir, subdir)
38+
if search_string in absolute_path and search_string not in dirs_list:
39+
dirs_list.append(absolute_path)
40+
return(dirs_list)
41+
42+
def search_files(search_string, rootdir):
43+
files_list=[]
44+
for rootdir, dirs, files in os.walk(rootdir):
45+
for name in files:
46+
file_path = os.path.join(rootdir, name)
47+
if search_string in file_path and search_string not in files_list:
48+
files_list.append(file_path)
49+
return(files_list)
50+
51+
def conversion(opi_subdir, bob_subdir, phoebusFolder):
52+
#Check the OS
53+
system = platform.system()
54+
install_path = phoebusFolder
55+
if system == "Linux" :
56+
java_path = os.path.join(install_path, 'java', 'linux-jdk-16.0.2', 'bin', 'java')
57+
classpath1 = os.path.join(install_path, 'javafx', 'linux', '*')
58+
classpath2 = os.path.join(install_path, 'lib', '*')
59+
classpath_str = classpath1 + ':' + classpath2
60+
opi_files = os.path.join (opi_subdir, "*.opi")
61+
62+
elif system == "Windows":
63+
java_path = os.path.join(install_path, 'java', 'windows-jdk-16.0.2', 'bin', 'java')
64+
classpath1 = os.path.join(install_path, 'javafx', 'windows', '*')
65+
classpath2 = os.path.join(install_path, 'lib', '*')
66+
classpath_str = classpath1 + ';' + classpath2
67+
opi_files = os.path.join (opi_subdir, "*.opi")
68+
69+
cmd = java_path + " -Xms2048m -Xmx2048m" + " -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel" + " -cp " + classpath_str + " org.csstudio.display.builder.model.Converter " + "-output " + bob_subdir + " " + opi_files
70+
subprocess.call(cmd, shell=True)
71+
return
72+
73+
def main():
74+
inputFolder = args.opi_folder
75+
phoebusFolder = args.phoebus_folder
76+
77+
#Delete former resized_opi folder if it exists
78+
for resized_dir in search_dirs("resized", inputFolder):
79+
if os.path.exists(resized_dir):
80+
print(f"Deleting the folder : {resized_dir}")
81+
shutil.rmtree(resized_dir)
82+
83+
#Check if there are .opi files in input folder
84+
opi_file_list = search_files(".opi", inputFolder)
85+
if opi_file_list == [] :
86+
print (f"Error: {inputFolder} does not contain .opi files")
87+
return
88+
89+
opi_dir_list_unique = []
90+
bob_dir_list_unique = []
91+
opi_resized_dir_list = []
92+
93+
#Check if inputFolder exists and is a folder
94+
if not os.path.isdir(inputFolder):
95+
print(f"Error: {inputFolder} does not exist or is not a folder")
96+
return
97+
opi_file_list = search_files(".opi", inputFolder)
98+
99+
#Resize opi and convert opi in bob
100+
for opi_file in opi_file_list:
101+
opi_subdir = os.path.dirname(opi_file)
102+
head, sep, tail = opi_file.partition("/opi/")
103+
opi_dir = head + sep
104+
105+
#Recreate the paths to the file inside bob and resized_opi folders
106+
sep_bob = re.sub("opi", "bob", sep)
107+
tail_bob = re.sub("opi", "bob", tail)
108+
path_to_bob_file = head + sep_bob + tail_bob
109+
sep_resized_opi = re.sub("opi", "resized_opi", sep)
110+
path_to_resized_opi_file = head + sep_resized_opi + tail
111+
112+
113+
if opi_subdir not in opi_dir_list_unique:
114+
opi_dir_list_unique.append(opi_subdir)
115+
bob_subdir = os.path.dirname(path_to_bob_file)
116+
117+
if not "opi" in opi_subdir:
118+
print(f"opi files in {opi_subdir} are not converted because they are not in a folder named 'opi' ")
119+
continue
120+
121+
#Replicate the opi folder in a bob folder
122+
if not os.path.exists(bob_subdir):
123+
shutil.copytree(opi_subdir, bob_subdir, symlinks = True, ignore=shutil.ignore_patterns('*.opi'))
124+
elif opi_subdir == opi_dir_list_unique[0] :
125+
print('bob folder already exists')
126+
127+
#Case where a opi/opi/ folder exists
128+
BobOpi_dir_list = search_dirs("opi", bob_subdir)
129+
if BobOpi_dir_list:
130+
for BobOpi in BobOpi_dir_list:
131+
if os.path.exists(BobOpi):
132+
shutil.rmtree(BobOpi)
133+
134+
#Resize
135+
opi_resized_dir = head + sep_resized_opi
136+
if opi_resized_dir not in opi_resized_dir_list:
137+
opi_resized_dir_list.append(opi_resized_dir)
138+
139+
if not os.path.exists(opi_resized_dir):
140+
print(f"Creating the folder : {opi_resized_dir}")
141+
shutil.copytree(opi_dir, opi_resized_dir, symlinks = True)
142+
143+
opiResized_file_list = search_files(".opi", opi_resized_dir)
144+
for opi_to_resize in opiResized_file_list:
145+
if not os.path.islink(opi_to_resize):
146+
print(f"Resizing : {opi_to_resize}")
147+
opi_resizing(opi_to_resize)
148+
else:
149+
print(f"{opi_to_resize} is a symbolic link")
150+
151+
#Conversion
152+
opi_resized_dir = os.path.dirname(path_to_resized_opi_file)
153+
conversion(opi_resized_dir, bob_subdir, phoebusFolder)
154+
155+
#Update the bob file
156+
bob_dir = head + sep_bob
157+
if bob_subdir not in bob_dir_list_unique:
158+
bob_dir_list_unique.append(bob_subdir)
159+
bob_file_list = search_files(".bob", bob_subdir)
160+
for bob_file in bob_file_list:
161+
bob_updating(bob_file, bob_dir)
162+
163+
#Recreate symbolic links inside bob dir
164+
if os.path.islink(opi_file) :
165+
path_to_opi = os.path.dirname(opi_file)
166+
path_to_bob = re.sub("opi", "bob", path_to_opi)
167+
file_name = os.path.basename (opi_file)
168+
bob_link = re.sub("opi", "bob", opi_file)
169+
os.remove(bob_link)
170+
source = os.readlink(opi_file)
171+
source_bob = re.sub("opi", "bob", source)
172+
destination = re.sub("opi", "bob", file_name)
173+
os.chdir(path_to_bob)
174+
os.symlink(source_bob, bob_link)
175+
176+
#Delete resized_opi folder
177+
for dir in search_dirs("resized_opi", inputFolder):
178+
if os.path.exists(dir):
179+
print(f"Deleting the folder : {dir}")
180+
shutil.rmtree(dir)
181+
182+
183+
184+
if __name__ == '__main__':
185+
186+
parser = argparse.ArgumentParser(description='This python scripts create the same bob folder architecture (with the same content, such as symbolic links, scripts or other documents) as the opi folder, resize CSS opi windows, convert all CSS opi files to Phoebus bob files, and then update the Phoebus bob files.')
187+
parser.add_argument('opi_folder', help='Path to the opi folder which contains the CSS opi files to convert. !!Prerequisit : the opi files have to be stored in a folder named opi')
188+
parser.add_argument('phoebus_folder', help='Path to the phoebus installation folder')
189+
190+
args = parser.parse_args()
191+
192+
main()

0 commit comments

Comments
 (0)