Salome HOME
[EDF] Taking SALOME launcher options into account through environment variable SALOME...
[modules/kernel.git] / bin / pythonpath_reduction.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 *-
3
4 ##############################################################
5 # This script reduce the pythonpath of salome environement.  #
6 # The single input of this script is install path of salome. #                                  #
7 ##############################################################
8
9 import argparse
10 import glob
11 import logging
12 import os
13 import shutil
14 import sys
15
16 from parseConfigFile import parseConfigFile
17
18 logging.basicConfig()
19 logger = logging.getLogger(os.path.basename(__file__))
20 logger.setLevel(logging.INFO)
21
22 IGNORE = ['__pycache__', '__init__.py', '.yamm', 'NEWS', 'README']
23
24
25 def remove(path):
26     logger.debug('Removing %r' % (path))
27     if os.path.islink(path):
28         os.unlink(path)
29     elif os.path.isdir(path):
30         shutil.rmtree(path)
31     else:
32         os.remove(path)
33
34
35 def copy(src, dst):
36     logger.debug('Copy %r to %r' % (src, dst))
37     if os.path.exists(dst):
38         remove(dst)
39     if not os.path.isdir(src):
40         shutil.copyfile(src, dst)
41     else:
42         shutil.copytree(src, dst)
43
44
45 def copy_or_link(src, dst):
46     if sys.platform in ('linux', 'linux2'):
47         if os.path.exists(dst):
48             current_dst = os.readlink(dst)
49             logger.warning('Destination link %r already exists and links to %r.' % (dst, current_dst))
50             logger.warning('It is overwritten to %r' % (src))
51             remove(dst)
52         os.symlink(src, dst)
53     else:
54         copy(src, dst)
55
56
57 if sys.version_info[0] < 3:
58     raise Exception("Must be using Python 3")
59
60
61 def main(salome_install_dir, context_file_name, env_file_name, ignore=None):
62     if ignore:
63         ignore = IGNORE + ignore
64     else:
65         ignore = IGNORE[::]
66
67     # new pythonpath initiation; creation a directory containing all python module for salome
68     salome_install_dir=os.path.abspath(salome_install_dir)
69     pythonpath_common = os.path.join(salome_install_dir, 'python_modules')
70     if os.path.exists(pythonpath_common):
71         remove(pythonpath_common)
72     os.mkdir(pythonpath_common)
73     new_pythonpath_list = []
74     new_pythonpath_list.append(pythonpath_common)
75
76     # parsing configuration file (cfg) to get old pythonpath
77     reserved_key = ['PYTHONPATH']
78     context_file = os.path.join(salome_install_dir, context_file_name)
79     context_file_sh = os.path.join(salome_install_dir, env_file_name)
80     backup_context_file = context_file + '.backup'
81     backup_context_file_sh = context_file_sh + '.backup'
82     if os.path.exists(backup_context_file):
83         logger.info("Recover context file %r from backup" % (context_file))
84         copy(backup_context_file, context_file)
85     if os.path.exists(backup_context_file_sh):
86         logger.info("Recover env file %r from backup" % (context_file_sh))
87         copy(backup_context_file_sh, context_file_sh)
88
89     if not os.path.exists(context_file) or not os.path.exists(context_file_sh):
90         raise Exception("Context and env files are not found in the salome install. "
91                         "Verify if %s and %s are present in the salome install path: %s"
92                         % (context_file_name, env_file_name, salome_install_dir))
93     configInfo = parseConfigFile(context_file, reserved_key)
94     configVars = configInfo.outputVariables
95     reservedDict = configInfo.reservedValues
96     configVarsDict = {k: v for (k, v) in configVars}
97
98     # Synchronize new pythonpath with the old
99     # Copy all the .egg files to the new directory of python module and list them in new single easy-install.pth
100     # If the module hasn't .egg file, we must copy all files from its pythonpath and paste them in the python module directory
101     # It's complicated to reduce pythonpath of paraview so for now we keep the old paraview pythonpath
102     pattern = "*.egg"
103     with open(os.path.join(pythonpath_common, 'easy-install.pth'), 'w') as easy_install:
104         for dirs in reservedDict[reserved_key[0]]:
105             for d in dirs.split(':'):
106                 egg_dir_list = glob.glob(os.path.join(d, pattern))
107                 if egg_dir_list:
108                     for egg_dir in egg_dir_list:
109                         egg_file = egg_dir.split('/')[-1]
110                         new_dir = os.path.join(pythonpath_common, egg_file)
111                         copy_or_link(egg_dir, new_dir)
112                         easy_install.write("./%s\n" % egg_file)
113                 else:
114                     for f in os.listdir(d):
115                         if f in ignore:
116                             continue
117                         full_file_srcpath = os.path.join(d, f)
118                         full_file_dstpath = os.path.join(pythonpath_common, f)
119                         copy_or_link(full_file_srcpath, full_file_dstpath)
120     # In the case of matplotlib, some prerequis are found matplotlib_root. They also need to be put in new directory of module python
121     try:
122         with open(os.path.join(pythonpath_common, 'easy-install.pth'), 'a') as easy_install:
123             MATPLOTLIB_ROOT = configVarsDict['MATPLOTLIB_HOME']
124             for d in os.listdir(MATPLOTLIB_ROOT):
125                 if ".egg" in d:
126                     copy_or_link(os.path.join(MATPLOTLIB_ROOT, d), os.path.join(pythonpath_common, d))
127                     easy_install.write("./%s\n" % d)
128     except KeyError:
129         logger.debug("Not found MATPLOTLIB_HOME variable in the .cfg")
130         logger.debug("Matplotlib isn't compiled with salome or maybe it is in the system package ")
131         logger.debug("If matplotlib is compiled with salome, we need define its install path with variable MATPLOTLIB_HOME")
132
133     # Fix for correct imports
134     import setuptools
135     try:
136         setup_tools_path = os.path.dirname(setuptools.__file__)
137     except AttributeError:
138         setup_tools_path = os.path.dirname(setuptools.__path__._path[0])
139     del setuptools
140     site_patch = os.path.join(setup_tools_path, 'site-patch.py')
141     shutil.copyfile(site_patch, os.path.join(pythonpath_common, "site.py"))
142
143     # Overwrite salome_context.cfg
144     # Backup context and env files
145     copy(context_file, backup_context_file)
146     copy(context_file_sh, backup_context_file_sh)
147     with open(context_file, 'r') as f:
148         lines = f.readlines()
149     with open(context_file, 'w') as f:
150         for line in lines:
151             if "ADD_TO_PYTHONPATH" not in line:
152                 f.write(line)
153     with open(context_file, 'a') as f:
154         f.write("#------ NEWPYTHONPATH ------\n")
155         for p in new_pythonpath_list:
156             f.write("ADD_TO_PYTHONPATH: %s\n" % p)
157
158     # Overwrite salome_prerequisites.sh
159     with open(context_file_sh, 'r') as f:
160         lines = f.readlines()
161     with open(context_file_sh, 'w') as f:
162         for line in lines:
163             if "PYTHONPATH" not in line:
164                 f.write(line)
165     with open(context_file_sh, 'a') as f:
166         f.write("#------ NEWPYTHONPATH ------\n")
167         for p in new_pythonpath_list:
168             f.write("export PYTHONPATH=%s:${PYTHONPATH}\n" % p)
169
170
171 if __name__ == '__main__':
172     parser = argparse.ArgumentParser()
173     parser.add_argument('-v', '--verbose', action='store_true', help='Verbose mode')
174     parser.add_argument('-c', '--context-file', default='salome_context.cfg',
175                         help='Context file name (default: %(default)s)')
176     parser.add_argument('-e', '--env-file', default='salome_prerequisites.sh',
177                         help='Env file name (default: %(default)s)')
178     parser.add_argument('-i', '--ignore', nargs='*',
179                         help='List of comma separated files to ignore')
180     parser.add_argument(dest='salome_install_dir', help='Directory of context and env files')
181     args = parser.parse_args()
182     if args.verbose:
183         logger.setLevel(logging.DEBUG)
184     main(args.salome_install_dir, args.context_file, args.env_file, args.ignore)