#
# Copyright (C) 2012-2020 Euclid Science Ground Segment
#
# This library is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3.0 of the License, or (at your option)
# any later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
'''
:date: Created on Apr 29, 2016
:author: Hubert Degaudenzi
'''
import os
import sys
import sysconfig
import re
from collections import OrderedDict
from ElementsKernel.System import SHLIB_VAR_NAME, DEFAULT_INSTALL_PREFIX
Type = ["executable", "library", "python", "configuration", "auxiliary"]
PATHSEP = os.pathsep
VARIABLE = {"executable": "PATH",
"library": SHLIB_VAR_NAME,
"python": "PYTHONPATH",
"configuration": "ELEMENTS_CONF_PATH",
"auxiliary": "ELEMENTS_AUX_PATH"}
SUFFIXES = {"executable": ["scripts", "bin"],
"library": ["lib"],
"python": ["python"],
"configuration": ["conf", "share/conf"],
"auxiliary": ["auxdir", "aux", "share/auxdir", "share/aux"]}
DEFAULT_INSTALL_LOCATIONS = {
"executable": [ os.path.join(DEFAULT_INSTALL_PREFIX, "bin")],
"library": [ os.path.join(DEFAULT_INSTALL_PREFIX, "lib64"),
os.path.join(DEFAULT_INSTALL_PREFIX, "lib"),
os.path.join(DEFAULT_INSTALL_PREFIX, "lib32")],
"python": [ sysconfig.get_path("purelib").replace(sys.prefix, DEFAULT_INSTALL_PREFIX)],
"configuration": [ os.path.join(DEFAULT_INSTALL_PREFIX, "share", "conf") ],
"auxiliary": [ os.path.join(DEFAULT_INSTALL_PREFIX, "share", "auxdir"),
os.path.join(DEFAULT_INSTALL_PREFIX, "share", "aux")]
}
HAS_SUBLEVELS = {
"executable": False,
"library": False,
"python": True,
"configuration": True,
"auxiliary": True
}
[docs]def getLocations(file_type="executable", exist_only=False, with_defaults=True):
"""
Get the locations of a type of file -- including the default ones
"""
location_list = getLocationsFromEnv(VARIABLE[file_type], exist_only)
if with_defaults:
location_list += DEFAULT_INSTALL_LOCATIONS[file_type]
if exist_only:
location_list = [p for p in location_list if os.path.exists(p)]
return location_list
[docs]def getPath(file_name, file_type="executable", raise_exception=True):
"""
Get full path to the file name searched in the file-type path
"""
location_list = getLocations(file_type)
result = getPathFromLocations(file_name, location_list)
if not result and raise_exception:
raise Exception("The %s file \"%s\" cannot be found!" % (file_type, file_name))
return result
[docs]def getLocationsFromEnv(path_variable, exist_only=False):
"""
Get the list of locations provided by the path
environment variable.
"""
env_content = os.environ.get(path_variable, None)
found_list = []
if env_content:
found_list = env_content.split(PATHSEP)
if exist_only:
found_list = [p for p in found_list if os.path.exists(p)]
return found_list
[docs]def getPathFromLocations(file_name, locations):
"""
Get the path to the searched file name from the
provided locations. The first found wins.
"""
for l in locations:
file_path = os.path.join(l, file_name)
if os.path.exists(file_path):
return file_path
return None
[docs]def getAllPathFromLocations(file_name, locations):
"""
Get all the paths to the searched file name from the
provided locations.
"""
file_list = []
for l in locations:
file_path = os.path.join(l, file_name)
if os.path.exists(file_path):
file_list.append(file_path)
return removeDuplicates(file_list)
[docs]def getPathFromEnvVariable(file_name, path_variable):
"""
Look for the first path valid in the <path_variable> environment
variable where is located the <file_name> file. It returns the
filename with the path or an empty string if not found. We assume that the
file_name also contains any sub directory under the <path_variable>
environment variable entry.
:param file_name: file name to look for can be "Some.txt" or "/" path
component like "SomeFolder/Some.txt"
:param path_variable: name of the environment variable to look into
:return: full path to the first match entry.
"""
location_list = getLocationsFromEnv(path_variable)
return getPathFromLocations(file_name, location_list)
[docs]def joinPath(path_list):
""" stupid wrapper to look like the C++ call """
return os.pathsep.join(path_list)
join = joinPath
[docs]def multiPathAppend(initial_locations, suffixes):
""" Function to append all the suffixes to
all the initial location
:param initial_locations: as quoted the initial paths to be
appended to
:param suffixes: the extensions to be appended.
"""
result = []
for l in initial_locations:
result += [os.path.join(l, s) for s in suffixes]
return result
[docs]def which(program):
""" Command to assert the existance of an executable
:param program: program path, absolute or relative
"""
def is_exe(fpath):
""" small function to check if the item is an executable """
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, _ = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
[docs]def pyVersionWhich(program, program3_prefix=None):
""" Version of which that returns the right executable
depending on the calling python version.
:param program: program path, absolute or relative
:param program3: program3 prefix,
"""
executable_name = None
python_version = ""
if not program3_prefix:
program3_prefix = program
m = re.match(r".*python(.*)$", sys.executable)
if m:
python_version = m.group(1)
if python_version:
executable_name = program3_prefix + python_version
else:
executable_name = program
return which(executable_name)
[docs]def getTargetPath(file_name, target_dir, target_name=None, use_stem=False):
""" Compute the target path for a copy/configuration of a file
:param file_name: the original file name with or without a stem
:param target_dir: the target directory
:param target_name: the target name if any
:param use_stem: choose if the stem (dirname) of the file_name will be used or only
the last component (basename) of the file_name path.
:return: the final target path for the copy/configuration.
"""
if target_name:
target_path = os.path.join(target_dir, target_name)
elif use_stem:
target_path = os.path.join(target_dir, file_name)
else:
target_path = os.path.join(target_dir, os.path.basename(file_name))
return target_path
[docs]def removeDuplicates(file_list):
""" stupid wrapper to look like the C++ call """
return list(OrderedDict.fromkeys(file_list))