From 55cd9a878d3170e066a57d96ef851af81e17a021 Mon Sep 17 00:00:00 2001 From: Konstantin Leontev Date: Tue, 10 Jan 2023 16:11:56 +0300 Subject: [PATCH] [bos #32522][EDF] SALOME on Demand. Added functions and refactored to support adding modules from extensions in GUI. --- bin/SalomeOnDemandTK/extension_unpacker.py | 52 ++++++- bin/SalomeOnDemandTK/extension_utilities.py | 142 ++++++++++++++++++++ bin/runSalomeOnDemand.py | 58 +------- 3 files changed, 193 insertions(+), 59 deletions(-) diff --git a/bin/SalomeOnDemandTK/extension_unpacker.py b/bin/SalomeOnDemandTK/extension_unpacker.py index 47355b772..57a5fe382 100644 --- a/bin/SalomeOnDemandTK/extension_unpacker.py +++ b/bin/SalomeOnDemandTK/extension_unpacker.py @@ -38,8 +38,9 @@ import json from traceback import format_exc from .extension_utilities import logger, \ - DFILE_EXT, ARCFILE_EXT, EXTDEPENDSON_KEY, \ - isvalid_filename, isvalid_dirname + DFILE_EXT, ARCFILE_EXT, EXTDEPENDSON_KEY, EXTCOMPONENT_KEY, \ + isvalid_filename, isvalid_dirname, ext_info_bykey, set_selext_env, get_app_root + def unpack_salomex(salome_root, salomex): """ @@ -50,7 +51,7 @@ def unpack_salomex(salome_root, salomex): salomex - a given salomex file to unpack. Returns: - None. + True if an ext was successfully unpacked. """ logger.debug('Starting unpack a salome extension file') @@ -58,7 +59,7 @@ def unpack_salomex(salome_root, salomex): # Check if provided filenames are valid if not isvalid_dirname(salome_root) or \ not isvalid_filename(salomex, ARCFILE_EXT): - return + return False try: with tarfile.open(salomex) as ext: @@ -80,7 +81,7 @@ def unpack_salomex(salome_root, salomex): if not os.path.isfile(depends_filename): logger.error('Cannot find %s for a module that extension depends on!', depends_filename) - return + return False # Unpack archive in the salome_root logger.debug('Extract all the files into %s...', salome_root) @@ -90,12 +91,53 @@ def unpack_salomex(salome_root, salomex): except (OSError, KeyError): logger.error(format_exc()) + return False + + return True + + +def install_salomex(salomex): + """ + Install a given salome extension into SALOME_APPLICATION_DIR. + + Args: + salomex - a given salomex file to unpack. + + Returns: + A list of components to be activated later. + """ + + logger.debug('Starting install a salome extension from %s', salomex) + + # Check if we have the salome root path + app_root = os.environ.get('SALOME_APPLICATION_DIR', '') + if not app_root: + # It should be set on the app start, but leave it here to run as a standalone script + logger.warning( + 'Env var SALOME_APPLICATION_DIR is not set! Try to set it going up from cur location.') + app_root = get_app_root() + + # Unpack an archive + if not unpack_salomex(app_root, salomex): + return [] + + # Set up an environment + # It's not clear at the moment what to do if it fails + ext_name, _ = os.path.splitext(os.path.basename(salomex)) + set_selext_env(app_root, ext_name) + + # Get components to activate later + components = ext_info_bykey(app_root, ext_name, EXTCOMPONENT_KEY) + + return components if components else [] if __name__ == '__main__': if len(sys.argv) == 3: arg_1, arg_2 = sys.argv[1:] # pylint: disable=unbalanced-tuple-unpacking unpack_salomex(arg_1, arg_2) + elif len(sys.argv) == 2: + install_salomex(sys.argv[1]) else: logger.error('You must provide all the arguments!') logger.info(unpack_salomex.__doc__) diff --git a/bin/SalomeOnDemandTK/extension_utilities.py b/bin/SalomeOnDemandTK/extension_utilities.py index ae2dc6ccb..eb60bf30a 100644 --- a/bin/SalomeOnDemandTK/extension_utilities.py +++ b/bin/SalomeOnDemandTK/extension_utilities.py @@ -33,9 +33,12 @@ Utilities and constants those help to deal with salome extension files. """ import os +import sys import logging import json from traceback import format_exc +from pathlib import Path +import importlib.util # Usually logging verbosity is set inside bin/runSalomeCommon.py when salome is starting. # Here we do just the same for a case if we call this package stand alone. @@ -43,6 +46,12 @@ FORMAT = '%(levelname)s : %(asctime)s : [%(filename)s:%(funcName)s:%(lineno)s] : logging.basicConfig(format=FORMAT, level=logging.DEBUG, force=False) logger = logging.getLogger() +# SalomeContext sets the logging verbosity level on its own, +# and we put it here, so it doesn't override the local format above. +#pylint: disable=wrong-import-position +import salomeContext +#pylint: enable=wrong-import-position + SALOME_EXTDIR = '__SALOME_EXT__' ARCFILE_EXT = 'salomex' BFILE_EXT = 'salomexb' @@ -124,6 +133,47 @@ def read_salomexd(file_path): return {} +def value_from_salomexd(file_path, key): + """ + Reads a content of a salomexd file and return a value for the given key. + + Args: + file_path - the path to the salomexd file. + key - the key to search an assigned value. + + Returns: + A value assigned to the given key if exist, otherwise None. + """ + + file_content = read_salomexd(file_path) + if key in file_content and file_content[key]: + logger.debug('Key: %s, value: %s', key, file_content[key]) + return file_content[key] + + logger.warning('Cannot get a value for key %s in salomexd file %s', key, file_path) + return None + + +def ext_info_bykey(salome_root, salomex_name, key): + """ + Search a salomexd file by ext name and return a value for the given key. + + Args: + install_dir - directory where the given extension is installed. + salomex_name - the given extension's name. + key - the key to search an assigned value. + + Returns: + A value for key in the given ext salomexd file. + """ + + salomexd = find_salomexd(salome_root, salomex_name) + if salomexd: + return value_from_salomexd(salomexd, key) + + return None + + def create_salomexb(name, included): """ Create a salomexb file from a list of included file names. @@ -453,3 +503,95 @@ def find_envpy(install_dir, salomex_name): """ return find_file(install_dir, salomex_name + ENVPYFILE_SUF) + + +def module_from_filename(filename): + """ + Create and execute a module by filename. + + Args: + filename - a given python filename. + + Returns: + Module. + """ + + # Get the module from the filename + basename = os.path.basename(filename) + module_name, _ = os.path.splitext(basename) + + spec = importlib.util.spec_from_file_location(module_name, filename) + if not spec: + logger.error('Could not get a spec for %s file!') + return None + + module = importlib.util.module_from_spec(spec) + if not module: + logger.error('Could not get a module for %s file!') + return None + + sys.modules[module_name] = module + + logger.debug('Execute %s module', module_name) + spec.loader.exec_module(module) + + return module + + +def set_selext_env(install_dir, salomex_name, context=None): + """ + Finds and run _env.py file for the given extension. + + Args: + install_dir - path to directory to check. + salomex_name - extension's name. + context - SalomeContext object. + + Returns: + True if an envpy file was found and run its init func. + """ + + logger.debug('Set an env for salome extension: %s...', salomex_name) + + # Set the root dir as env variable + if not context: + context = salomeContext.SalomeContext(None) + context.setVariable('SALOME_APPLICATION_DIR', install_dir, overwrite=False) + + # Find env file + ext_envpy = find_envpy(install_dir, salomex_name) + if not ext_envpy: + return False + + # Get a module + envpy_module = module_from_filename(ext_envpy) + if not envpy_module: + return False + + # Set env if we have something to set + ext_root = os.path.join(install_dir, SALOME_EXTDIR) + if hasattr(envpy_module, 'init'): + envpy_module.init(context, ext_root) + return True + else: + logger.warning('Env file %s doesnt have init func:!', ext_envpy) + + logger.warning('Setting an env for salome extension %s failed!', salomex_name) + return False + + +def get_app_root(levels_up=5): + """ + Finds an app root by going up on the given steps. + + Args: + levels_up - steps up in dir hierarchy relative to the current file. + + Returns: + Path to the app root. + """ + + app_root = str(Path(__file__).resolve().parents[levels_up - 1]) + logger.debug('App root: %s', app_root) + + return app_root diff --git a/bin/runSalomeOnDemand.py b/bin/runSalomeOnDemand.py index 69d48b00f..a54a1ac28 100755 --- a/bin/runSalomeOnDemand.py +++ b/bin/runSalomeOnDemand.py @@ -31,45 +31,10 @@ import os import sys -import importlib.util -from pathlib import Path import salomeContext from SalomeOnDemandTK.extension_utilities import logger, \ - DFILE_EXT, SALOME_EXTDIR, \ - list_files_ext, find_envpy - - -def module_from_filename(filename): - """ - Create and execute a module by filename. - - Args: - filename - a given python filename. - - Returns: - Module. - """ - - # Get the module from the filename - basename = os.path.basename(filename) - module_name, _ = os.path.splitext(basename) - - spec = importlib.util.spec_from_file_location(module_name, filename) - if not spec: - logger.error('Could not get a spec for %s file!') - return None - - module = importlib.util.module_from_spec(spec) - if not module: - logger.error('Could not get a module for %s file!') - return None - - sys.modules[module_name] = module - - logger.debug('Execute %s module', module_name) - spec.loader.exec_module(module) - - return module + DFILE_EXT, \ + list_files_ext, set_selext_env, get_app_root def set_ext_env(app_name='', version=''): @@ -87,9 +52,7 @@ def set_ext_env(app_name='', version=''): logger.debug('Set an env for app: %s, version: %s...', app_name, version) # Get the root directory - levels_up = 4 - app_root = str(Path(__file__).resolve().parents[levels_up - 1]) - logger.debug('App root: %s', app_root) + app_root = get_app_root() # Find and source all _env.py files for installed extensions installed_ext = list_files_ext(app_root, DFILE_EXT) @@ -103,24 +66,11 @@ def set_ext_env(app_name='', version=''): context.setVariable('SALOME_APPLICATION_DIR', app_root, overwrite=True) # Execute env file as a module - ext_root = os.path.join(app_root, SALOME_EXTDIR) for salomexd in installed_ext: salomexd_name = os.path.basename(salomexd) ext_name, _ = os.path.splitext(salomexd_name) - # Find env file - ext_envpy = find_envpy(app_root, ext_name) - if not ext_envpy: - continue - - # Get a module - envpy_module = module_from_filename(ext_envpy) - if not envpy_module: - continue - - # Set env if we have something to set - if hasattr(envpy_module, 'init'): - envpy_module.init(context, ext_root) + set_selext_env(app_root, ext_name, context) if __name__ == "__main__": -- 2.30.2