| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| """This file generates shell code for the setup.SHELL scripts to set environment variables.""" |
|
|
| from __future__ import print_function |
|
|
| import argparse |
| import copy |
| import errno |
| import os |
| import platform |
| import sys |
|
|
| CATKIN_MARKER_FILE = '.catkin' |
|
|
| system = platform.system() |
| IS_DARWIN = (system == 'Darwin') |
| IS_WINDOWS = (system == 'Windows') |
|
|
| PATH_TO_ADD_SUFFIX = ['bin'] |
| if IS_WINDOWS: |
| |
| |
| PATH_TO_ADD_SUFFIX.extend([['lib', os.path.join('lib', 'x86_64-linux-gnu')]]) |
|
|
| |
| ENV_VAR_SUBFOLDERS = { |
| 'CMAKE_PREFIX_PATH': '', |
| 'LD_LIBRARY_PATH' if not IS_DARWIN else 'DYLD_LIBRARY_PATH': ['lib', os.path.join('lib', 'x86_64-linux-gnu')], |
| 'PATH': PATH_TO_ADD_SUFFIX, |
| 'PKG_CONFIG_PATH': [os.path.join('lib', 'pkgconfig'), os.path.join('lib', 'x86_64-linux-gnu', 'pkgconfig')], |
| 'PYTHONPATH': 'lib/python3/dist-packages', |
| } |
|
|
|
|
| def rollback_env_variables(environ, env_var_subfolders): |
| """ |
| Generate shell code to reset environment variables. |
| |
| by unrolling modifications based on all workspaces in CMAKE_PREFIX_PATH. |
| This does not cover modifications performed by environment hooks. |
| """ |
| lines = [] |
| unmodified_environ = copy.copy(environ) |
| for key in sorted(env_var_subfolders.keys()): |
| subfolders = env_var_subfolders[key] |
| if not isinstance(subfolders, list): |
| subfolders = [subfolders] |
| value = _rollback_env_variable(unmodified_environ, key, subfolders) |
| if value is not None: |
| environ[key] = value |
| lines.append(assignment(key, value)) |
| if lines: |
| lines.insert(0, comment('reset environment variables by unrolling modifications based on all workspaces in CMAKE_PREFIX_PATH')) |
| return lines |
|
|
|
|
| def _rollback_env_variable(environ, name, subfolders): |
| """ |
| For each catkin workspace in CMAKE_PREFIX_PATH remove the first entry from env[NAME] matching workspace + subfolder. |
| |
| :param subfolders: list of str '' or subfoldername that may start with '/' |
| :returns: the updated value of the environment variable. |
| """ |
| value = environ[name] if name in environ else '' |
| env_paths = [path for path in value.split(os.pathsep) if path] |
| value_modified = False |
| for subfolder in subfolders: |
| if subfolder: |
| if subfolder.startswith(os.path.sep) or (os.path.altsep and subfolder.startswith(os.path.altsep)): |
| subfolder = subfolder[1:] |
| if subfolder.endswith(os.path.sep) or (os.path.altsep and subfolder.endswith(os.path.altsep)): |
| subfolder = subfolder[:-1] |
| for ws_path in _get_workspaces(environ, include_fuerte=True, include_non_existing=True): |
| path_to_find = os.path.join(ws_path, subfolder) if subfolder else ws_path |
| path_to_remove = None |
| for env_path in env_paths: |
| env_path_clean = env_path[:-1] if env_path and env_path[-1] in [os.path.sep, os.path.altsep] else env_path |
| if env_path_clean == path_to_find: |
| path_to_remove = env_path |
| break |
| if path_to_remove: |
| env_paths.remove(path_to_remove) |
| value_modified = True |
| new_value = os.pathsep.join(env_paths) |
| return new_value if value_modified else None |
|
|
|
|
| def _get_workspaces(environ, include_fuerte=False, include_non_existing=False): |
| """ |
| Based on CMAKE_PREFIX_PATH return all catkin workspaces. |
| |
| :param include_fuerte: The flag if paths starting with '/opt/ros/fuerte' should be considered workspaces, ``bool`` |
| """ |
| |
| env_name = 'CMAKE_PREFIX_PATH' |
| value = environ[env_name] if env_name in environ else '' |
| paths = [path for path in value.split(os.pathsep) if path] |
| |
| workspaces = [path for path in paths if os.path.isfile(os.path.join(path, CATKIN_MARKER_FILE)) or (include_fuerte and path.startswith('/opt/ros/fuerte')) or (include_non_existing and not os.path.exists(path))] |
| return workspaces |
|
|
|
|
| def prepend_env_variables(environ, env_var_subfolders, workspaces): |
| """Generate shell code to prepend environment variables for the all workspaces.""" |
| lines = [] |
| lines.append(comment('prepend folders of workspaces to environment variables')) |
|
|
| paths = [path for path in workspaces.split(os.pathsep) if path] |
|
|
| prefix = _prefix_env_variable(environ, 'CMAKE_PREFIX_PATH', paths, '') |
| lines.append(prepend(environ, 'CMAKE_PREFIX_PATH', prefix)) |
|
|
| for key in sorted(key for key in env_var_subfolders.keys() if key != 'CMAKE_PREFIX_PATH'): |
| subfolder = env_var_subfolders[key] |
| prefix = _prefix_env_variable(environ, key, paths, subfolder) |
| lines.append(prepend(environ, key, prefix)) |
| return lines |
|
|
|
|
| def _prefix_env_variable(environ, name, paths, subfolders): |
| """ |
| Return the prefix to prepend to the environment variable NAME. |
| |
| Adding any path in NEW_PATHS_STR without creating duplicate or empty items. |
| """ |
| value = environ[name] if name in environ else '' |
| environ_paths = [path for path in value.split(os.pathsep) if path] |
| checked_paths = [] |
| for path in paths: |
| if not isinstance(subfolders, list): |
| subfolders = [subfolders] |
| for subfolder in subfolders: |
| path_tmp = path |
| if subfolder: |
| path_tmp = os.path.join(path_tmp, subfolder) |
| |
| if not os.path.exists(path_tmp): |
| continue |
| |
| if path_tmp not in environ_paths and path_tmp not in checked_paths: |
| checked_paths.append(path_tmp) |
| prefix_str = os.pathsep.join(checked_paths) |
| if prefix_str != '' and environ_paths: |
| prefix_str += os.pathsep |
| return prefix_str |
|
|
|
|
| def assignment(key, value): |
| if not IS_WINDOWS: |
| return 'export %s="%s"' % (key, value) |
| else: |
| return 'set %s=%s' % (key, value) |
|
|
|
|
| def comment(msg): |
| if not IS_WINDOWS: |
| return '# %s' % msg |
| else: |
| return 'REM %s' % msg |
|
|
|
|
| def prepend(environ, key, prefix): |
| if key not in environ or not environ[key]: |
| return assignment(key, prefix) |
| if not IS_WINDOWS: |
| return 'export %s="%s$%s"' % (key, prefix, key) |
| else: |
| return 'set %s=%s%%%s%%' % (key, prefix, key) |
|
|
|
|
| def find_env_hooks(environ, cmake_prefix_path): |
| """Generate shell code with found environment hooks for the all workspaces.""" |
| lines = [] |
| lines.append(comment('found environment hooks in workspaces')) |
|
|
| generic_env_hooks = [] |
| generic_env_hooks_workspace = [] |
| specific_env_hooks = [] |
| specific_env_hooks_workspace = [] |
| generic_env_hooks_by_filename = {} |
| specific_env_hooks_by_filename = {} |
| generic_env_hook_ext = 'bat' if IS_WINDOWS else 'sh' |
| specific_env_hook_ext = environ['CATKIN_SHELL'] if not IS_WINDOWS and 'CATKIN_SHELL' in environ and environ['CATKIN_SHELL'] else None |
| |
| workspaces = [path for path in cmake_prefix_path.split(os.pathsep) if path and os.path.isfile(os.path.join(path, CATKIN_MARKER_FILE))] |
| for workspace in reversed(workspaces): |
| env_hook_dir = os.path.join(workspace, 'etc', 'catkin', 'profile.d') |
| if os.path.isdir(env_hook_dir): |
| for filename in sorted(os.listdir(env_hook_dir)): |
| if filename.endswith('.%s' % generic_env_hook_ext): |
| |
| if filename in generic_env_hooks_by_filename: |
| i = generic_env_hooks.index(generic_env_hooks_by_filename[filename]) |
| generic_env_hooks.pop(i) |
| generic_env_hooks_workspace.pop(i) |
| |
| generic_env_hooks.append(os.path.join(env_hook_dir, filename)) |
| generic_env_hooks_workspace.append(workspace) |
| generic_env_hooks_by_filename[filename] = generic_env_hooks[-1] |
| elif specific_env_hook_ext is not None and filename.endswith('.%s' % specific_env_hook_ext): |
| |
| if filename in specific_env_hooks_by_filename: |
| i = specific_env_hooks.index(specific_env_hooks_by_filename[filename]) |
| specific_env_hooks.pop(i) |
| specific_env_hooks_workspace.pop(i) |
| |
| specific_env_hooks.append(os.path.join(env_hook_dir, filename)) |
| specific_env_hooks_workspace.append(workspace) |
| specific_env_hooks_by_filename[filename] = specific_env_hooks[-1] |
| env_hooks = generic_env_hooks + specific_env_hooks |
| env_hooks_workspace = generic_env_hooks_workspace + specific_env_hooks_workspace |
| count = len(env_hooks) |
| lines.append(assignment('_CATKIN_ENVIRONMENT_HOOKS_COUNT', count)) |
| for i in range(count): |
| lines.append(assignment('_CATKIN_ENVIRONMENT_HOOKS_%d' % i, env_hooks[i])) |
| lines.append(assignment('_CATKIN_ENVIRONMENT_HOOKS_%d_WORKSPACE' % i, env_hooks_workspace[i])) |
| return lines |
|
|
|
|
| def _parse_arguments(args=None): |
| parser = argparse.ArgumentParser(description='Generates code blocks for the setup.SHELL script.') |
| parser.add_argument('--extend', action='store_true', help='Skip unsetting previous environment variables to extend context') |
| parser.add_argument('--local', action='store_true', help='Only consider this prefix path and ignore other prefix path in the environment') |
| return parser.parse_known_args(args=args)[0] |
|
|
|
|
| if __name__ == '__main__': |
| try: |
| try: |
| args = _parse_arguments() |
| except Exception as e: |
| print(e, file=sys.stderr) |
| sys.exit(1) |
|
|
| if not args.local: |
| |
| CMAKE_PREFIX_PATH = r'/home/agilex/agilex_ws/devel;/opt/ros/noetic'.split(';') |
| else: |
| |
| CMAKE_PREFIX_PATH = [] |
| |
| base_path = os.path.dirname(__file__) |
| |
| |
| if os.path.sep != '/': |
| base_path = base_path.replace(os.path.sep, '/') |
|
|
| if base_path not in CMAKE_PREFIX_PATH: |
| CMAKE_PREFIX_PATH.insert(0, base_path) |
| CMAKE_PREFIX_PATH = os.pathsep.join(CMAKE_PREFIX_PATH) |
|
|
| environ = dict(os.environ) |
| lines = [] |
| if not args.extend: |
| lines += rollback_env_variables(environ, ENV_VAR_SUBFOLDERS) |
| lines += prepend_env_variables(environ, ENV_VAR_SUBFOLDERS, CMAKE_PREFIX_PATH) |
| lines += find_env_hooks(environ, CMAKE_PREFIX_PATH) |
| print('\n'.join(lines)) |
|
|
| |
| sys.stdout.flush() |
| except IOError as e: |
| |
| |
| if e.errno == errno.EPIPE: |
| print(e, file=sys.stderr) |
| sys.exit(2) |
| raise |
|
|
| sys.exit(0) |
|
|