Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions ament_package/template/package_level/local_setup.fish.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# generated from ament_package/template/package_level/local_setup.fish.in

# since this file is sourced use the destination set at configure time
# and override it with COLCON_CURRENT_PREFIX when provided
set -l AMENT_CURRENT_PREFIX "@CMAKE_INSTALL_PREFIX@"
if test -n "$COLCON_CURRENT_PREFIX"
set AMENT_CURRENT_PREFIX "$COLCON_CURRENT_PREFIX"
end
if not test -d "$AMENT_CURRENT_PREFIX"
echo "The compile-time prefix path '$AMENT_CURRENT_PREFIX' doesn't exist. \
Consider sourcing a different shell extension." 1>&2
set -e AMENT_CURRENT_PREFIX
return 1
end
set -l _package_local_setup_AMENT_CURRENT_PREFIX "$AMENT_CURRENT_PREFIX"

# function to append values to environment variables
# using colons as separators and avoiding leading separators
function ament_append_value
set -l _name $argv[1]
set -l _val $argv[2]
if set -q $_name; and test -n "$$_name"
set -gx $_name "$$_name:$_val"
else
set -gx $_name "$_val"
end
end

# unset AMENT_ENVIRONMENT_HOOKS
# if not appending to them for return
if not set -q AMENT_RETURN_ENVIRONMENT_HOOKS
set -e AMENT_ENVIRONMENT_HOOKS
end

# restore AMENT_CURRENT_PREFIX before evaluating environment hooks
set AMENT_CURRENT_PREFIX "$_package_local_setup_AMENT_CURRENT_PREFIX"

# list all environment hooks of this package
@ENVIRONMENT_HOOKS@

functions -e ament_append_value

# source all shell-specific environment hooks of this package
# if not returning them
if not set -q AMENT_RETURN_ENVIRONMENT_HOOKS
for _hook in (string split ":" -- "$AMENT_ENVIRONMENT_HOOKS")
if string match -q -- "*.fish" "$_hook"
set -gx AMENT_CURRENT_PREFIX \
"$_package_local_setup_AMENT_CURRENT_PREFIX"
if test -f "$_hook"
if test -n "$AMENT_TRACE_SETUP_FILES"
echo "# source \"$_hook\""
end
source "$_hook"
end
end
end
set -e AMENT_ENVIRONMENT_HOOKS
end

set -e _package_local_setup_AMENT_CURRENT_PREFIX
# reset AMENT_CURRENT_PREFIX after each package
# allowing to source multiple package-level setup files
set -e AMENT_CURRENT_PREFIX
81 changes: 79 additions & 2 deletions ament_package/template/prefix_level/_local_setup_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@
FORMAT_STR_INVOKE_SCRIPT = None
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = None

# Track primary extension so helpers can apply shell-specific behavior.
PRIMARY_EXTENSION = None

DSV_TYPE_APPEND_NON_DUPLICATE = 'append-non-duplicate'
DSV_TYPE_PREPEND_NON_DUPLICATE = 'prepend-non-duplicate'
DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS = 'prepend-non-duplicate-if-exists'
DSV_TYPE_SET = 'set'
DSV_TYPE_SET_IF_UNSET = 'set-if-unset'
DSV_TYPE_SOURCE = 'source'

# Fish treats PATH / MANPATH / CDPATH as list variables.
# Use fish list prepend/append syntax for these vars.
_FISH_LIST_VARS = {'PATH', 'MANPATH', 'CDPATH'}


def main(argv=sys.argv[1:]): # noqa: D103
global FORMAT_STR_COMMENT_LINE
Expand All @@ -30,6 +37,7 @@ def main(argv=sys.argv[1:]): # noqa: D103
global FORMAT_STR_INVOKE_SCRIPT
global FORMAT_STR_REMOVE_LEADING_SEPARATOR
global FORMAT_STR_REMOVE_TRAILING_SEPARATOR
global PRIMARY_EXTENSION

parser = argparse.ArgumentParser(
description='Output shell commands for the packages in topological '
Expand All @@ -42,6 +50,8 @@ def main(argv=sys.argv[1:]): # noqa: D103
help='The additional file extension to be considered')
args = parser.parse_args(argv)

PRIMARY_EXTENSION = args.primary_extension

if args.primary_extension == 'sh':
FORMAT_STR_COMMENT_LINE = '# {comment}'
FORMAT_STR_SET_ENV_VAR = 'export {name}="{value}"'
Expand All @@ -61,6 +71,31 @@ def main(argv=sys.argv[1:]): # noqa: D103
'call:_ament_prefix_bat_strip_leading_semicolon "{name}"'
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = \
'call:_ament_prefix_bat_strip_trailing_semicolon "{name}"'
elif args.primary_extension == 'fish':
FORMAT_STR_COMMENT_LINE = '# {comment}'
FORMAT_STR_SET_ENV_VAR = 'set -gx {name} "{value}"'
FORMAT_STR_USE_ENV_VAR = '${name}'
# Keep AMENT_CURRENT_PREFIX local to this begin/end block
# so that it doesn't affect other scripts that are sourced.
FORMAT_STR_INVOKE_SCRIPT = (
'begin\n'
' set -lx AMENT_CURRENT_PREFIX "{prefix}"\n'
' if test -f "{script_path}"\n'
' if test -n "$AMENT_TRACE_SETUP_FILES"\n'
' echo "# source \\"{script_path}\\""\n'
' end\n'
' source "{script_path}"\n'
' else\n'
' echo "not found: \\"{script_path}\\"" 1>&2\n'
' end\n'
'end'
)
FORMAT_STR_REMOVE_LEADING_SEPARATOR = (
"set -gx {name} (string replace --regex '^:' '' -- \"${name}\")"
)
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = (
"set -gx {name} (string replace --regex ':$' '' -- \"${name}\")"
)
else:
assert False, 'Unknown primary extension: ' + args.primary_extension

Expand Down Expand Up @@ -352,6 +387,22 @@ def _append_unique_value(name, value):
env_state[name] = set(os.environ[name].split(os.pathsep))
else:
env_state[name] = set()

if PRIMARY_EXTENSION == 'fish' and name in _FISH_LIST_VARS:
# Fish list variables: use list-append syntax to avoid space-joining.
if value not in env_state[name]:
env_state[name].add(value)
line = (
'contains -- "{value}" ${name}; '
'or set -gx {name} ${name} "{value}"'
).format(name=name, value=value)
else:
if not _include_comments():
return []
line = FORMAT_STR_COMMENT_LINE.format_map(
{'comment': 'already in {}: {}'.format(name, value)})
return [line]

# append even if the variable has not been set yet, in case a shell script sets the
# same variable without the knowledge of this Python script.
# later _remove_ending_separators() will cleanup any unintentional trailing separator
Expand All @@ -373,6 +424,22 @@ def _prepend_unique_value(name, value):
env_state[name] = set(os.environ[name].split(os.pathsep))
else:
env_state[name] = set()

if PRIMARY_EXTENSION == 'fish' and name in _FISH_LIST_VARS:
# Fish list variables: use list-prepend syntax to avoid space-joining.
if value not in env_state[name]:
env_state[name].add(value)
line = (
'contains -- "{value}" ${name}; '
'or set -gx {name} "{value}" ${name}'
).format(name=name, value=value)
else:
if not _include_comments():
return []
line = FORMAT_STR_COMMENT_LINE.format_map(
{'comment': 'already in {}: {}'.format(name, value)})
return [line]

# prepend even if the variable has not been set yet, in case a shell script sets the
# same variable without the knowledge of this Python script.
# later _remove_ending_separators() will cleanup any unintentional trailing separator
Expand All @@ -394,6 +461,10 @@ def _remove_ending_separators():
# skip variables that already had values before this script started prepending
if name in os.environ:
continue
# Fish list variables don't use the colon-string approach so they
# never accumulate stray separators.
if PRIMARY_EXTENSION == 'fish' and name in _FISH_LIST_VARS:
continue
commands += [
FORMAT_STR_REMOVE_LEADING_SEPARATOR.format_map({'name': name}),
FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map({'name': name})]
Expand All @@ -408,8 +479,14 @@ def _set(name, value):


def _set_if_unset(name, value):
line = FORMAT_STR_SET_ENV_VAR.format_map(
{'name': name, 'value': value})
if PRIMARY_EXTENSION == 'fish':
# Fish: only set when NAME is unset or empty.
# `set -q` checks existence; `test -n` checks non-empty value.
line = 'set -q {name}; and test -n "${name}"; or set -gx {name} "{value}"'.format(
name=name, value=value)
else:
line = FORMAT_STR_SET_ENV_VAR.format_map(
{'name': name, 'value': value})
if env_state.get(name, os.environ.get(name)):
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
return [line]
Expand Down
44 changes: 44 additions & 0 deletions ament_package/template/prefix_level/local_setup.fish.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# generated from ament_package/template/prefix_level/local_setup.fish.in

# Prefer AMENT_CURRENT_PREFIX (set by setup.fish); otherwise use install-time prefix.
set -l _ament_prefix_fish_AMENT_CURRENT_PREFIX "@CMAKE_INSTALL_PREFIX@"
if test -n "$AMENT_CURRENT_PREFIX"
set _ament_prefix_fish_AMENT_CURRENT_PREFIX "$AMENT_CURRENT_PREFIX"
end

if not test -d "$_ament_prefix_fish_AMENT_CURRENT_PREFIX"
echo "The build-time prefix \"$_ament_prefix_fish_AMENT_CURRENT_PREFIX\" \
doesn't exist. Either source a script for a different shell or set \
AMENT_CURRENT_PREFIX explicitly." 1>&2
set -e _ament_prefix_fish_AMENT_CURRENT_PREFIX
return 1
end

# Locate a Python interpreter.
set -l _ament_python_executable "@ament_package_PYTHON_EXECUTABLE@"
if test -n "$AMENT_PYTHON_EXECUTABLE"
set _ament_python_executable "$AMENT_PYTHON_EXECUTABLE"
end
if not test -f "$_ament_python_executable"
if command -v python3 > /dev/null 2>&1
set _ament_python_executable (python3 -c "import sys; print(sys.executable)")
else
echo "error: unable to find a python3 executable" 1>&2
set -e _ament_prefix_fish_AMENT_CURRENT_PREFIX
return 1
end
end

# Generate fish setup commands in topological order and source them.
# psub turns Python stdout into a real file path for source.
# Generated commands use fish-native env handling (set -gx and list PATH).
if test -n "$AMENT_TRACE_SETUP_FILES"
echo "# source (\"$_ament_python_executable\" \
\"$_ament_prefix_fish_AMENT_CURRENT_PREFIX/_local_setup_util.py\" fish | psub)"
end

source (command "$_ament_python_executable" \
"$_ament_prefix_fish_AMENT_CURRENT_PREFIX/_local_setup_util.py" fish | psub)

set -e _ament_python_executable
set -e _ament_prefix_fish_AMENT_CURRENT_PREFIX
56 changes: 56 additions & 0 deletions ament_package/template/prefix_level/setup.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# copied from ament_package/template/prefix_level/setup.fish

# Determine prefix from this script's location at runtime.
# 'status -f' gives the path of the currently sourced file in fish.
set -l AMENT_CURRENT_PREFIX (builtin realpath (dirname (status -f)))

# trace output
if test -n "$AMENT_TRACE_SETUP_FILES"
echo "# source \"$AMENT_CURRENT_PREFIX/local_setup.fish\""
end

# Build ordered prefixes (same order as setup.sh.in) for overlay workspaces.
# Keep dedup inline: fish functions can't update caller local vars.
set -l _UNIQUE_PREFIX_PATH
set -l _parent_index \
"$AMENT_CURRENT_PREFIX/share/ament_index/resource_index/parent_prefix_path"

if test -d "$_parent_index"
for _resource in (command ls "$_parent_index" 2>/dev/null | command sort)
read -z _content < "$_parent_index/$_resource" 2>/dev/null; or set _content ""
set -l _paths (string split ":" -- "$_content")
# Reverse the list (similar to setup.sh)
set -l _reversed
for _p in $_paths
if test "$_p" = "{prefix}"
set _p "$AMENT_CURRENT_PREFIX"
end
set _reversed "$_p" $_reversed
end
for _p in $_reversed
if not contains -- "$_p" $_UNIQUE_PREFIX_PATH
set -a _UNIQUE_PREFIX_PATH "$_p"
end
end
end
end

# Always include the current prefix last (highest priority).
if not contains -- "$AMENT_CURRENT_PREFIX" $_UNIQUE_PREFIX_PATH
set -a _UNIQUE_PREFIX_PATH "$AMENT_CURRENT_PREFIX"
end

# Source local_setup.fish for each prefix in order.
for _prefix_path in $_UNIQUE_PREFIX_PATH
set -gx AMENT_CURRENT_PREFIX "$_prefix_path"
if test -f "$_prefix_path/local_setup.fish"
if test -n "$AMENT_TRACE_SETUP_FILES"
echo "# source \"$_prefix_path/local_setup.fish\""
end
source "$_prefix_path/local_setup.fish"
end
end

set -e AMENT_CURRENT_PREFIX
set -e _UNIQUE_PREFIX_PATH
set -e _parent_index
2 changes: 2 additions & 0 deletions ament_package/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def get_package_level_template_names(all_platforms=False):
names = ['local_setup.%s.in' % ext for ext in [
'bash',
'bat',
'fish',
'sh',
'zsh',
]]
Expand All @@ -52,6 +53,7 @@ def get_prefix_level_template_names(*, all_platforms=False):
]
names = ['local_setup.%s' % ext for ext in extensions] + \
['setup.%s' % ext for ext in extensions] + \
['local_setup.fish.in', 'setup.fish'] + \
['_local_setup_util.py']
Comment thread
cottsay marked this conversation as resolved.
if not all_platforms:
names = [name for name in names if _is_platform_specific_extension(name)]
Expand Down