Skip to content

Commit

Permalink
Add support for appending to environment variables (#130)
Browse files Browse the repository at this point in the history
This works largely the same as 'prepend-non-duplicate', but instead puts
the candidate value at the end of the target variable.

Signed-off-by: Scott K Logan <logans@cottsay.net>
  • Loading branch information
cottsay authored Dec 4, 2021
1 parent 46571c0 commit 37f9a1f
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 6 deletions.
33 changes: 32 additions & 1 deletion ament_package/template/package_level/local_setup.bat.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ set "AMENT_CURRENT_PREFIX="
goto:eof


:: Append non-duplicate values to environment variables
:: Append values to environment variables
:: using semicolons as separators and avoiding leading separators.
:: first argument: the name of the result variable
:: second argument: the value
Expand All @@ -45,6 +45,37 @@ goto:eof
)
goto:eof

:: Append non-duplicate values to environment variables
:: using semicolons as separators and avoiding trailing separators.
:: first argument: the name of the result variable
:: second argument: the value
:ament_append_unique_value
setlocal enabledelayedexpansion
:: arguments
set "listname=%~1"
set "value=%~2"
:: expand the list variable
set "list=!%listname%!"
:: check if the list contains the value
set "is_duplicate="
if "%list%" NEQ "" (
for %%v in ("%list:;=";"%") do (
if "%%~v" == "%value%" set "is_duplicate=1"
)
)
:: if it is not a duplicate append it
if "%is_duplicate%" == "" (
:: if not empty, append a semi-colon
if "!list!" NEQ "" set "list=!list!;"
:: append the value
set "list=!list!%value%"
)
endlocal & (
:: set result variable in parent scope
set "%~1=%list%"
)
goto:eof

:: Call the specified batch file and output the name when tracing is requested.
:: first argument: the batch file
:call_file
Expand Down
51 changes: 51 additions & 0 deletions ament_package/template/package_level/local_setup.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,57 @@ ament_append_value() {
unset _listname
}

# function to append non-duplicate values to environment variables
# using colons as separators and avoiding leading separators
ament_append_unique_value() {
# arguments
_listname=$1
_value=$2
#echo "listname $_listname"
#eval echo "list value \$$_listname"
#echo "value $_value"

# check if the list contains the value
eval _values=\$$_listname
_duplicate=
_ament_append_unique_value_IFS=$IFS
IFS=":"
if [ "$AMENT_SHELL" = "zsh" ]; then
ament_zsh_to_array _values
fi
for _item in $_values; do
# ignore empty strings
if [ -z "$_item" ]; then
continue
fi
if [ $_item = $_value ]; then
_duplicate=1
fi
done
unset _item

# append only non-duplicates
if [ -z "$_duplicate" ]; then
# avoid leading separator
if [ -z "$_values" ]; then
eval $_listname=\"$_value\"
#eval echo "set list \$$_listname"
else
# field separator must not be a colon
unset IFS
eval $_listname=\"\$$_listname:$_value\"
#eval echo "append list \$$_listname"
fi
fi
IFS=$_ament_append_unique_value_IFS
unset _ament_append_unique_value_IFS
unset _duplicate
unset _values

unset _value
unset _listname
}

# function to prepend non-duplicate values to environment variables
# using colons as separators and avoiding trailing separators
ament_prepend_unique_value() {
Expand Down
42 changes: 37 additions & 5 deletions ament_package/template/prefix_level/_local_setup_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
FORMAT_STR_INVOKE_SCRIPT = None
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = 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'
Expand All @@ -27,6 +28,7 @@ def main(argv=sys.argv[1:]): # noqa: D103
global FORMAT_STR_SET_ENV_VAR
global FORMAT_STR_USE_ENV_VAR
global FORMAT_STR_INVOKE_SCRIPT
global FORMAT_STR_REMOVE_LEADING_SEPARATOR
global FORMAT_STR_REMOVE_TRAILING_SEPARATOR

parser = argparse.ArgumentParser(
Expand All @@ -46,6 +48,8 @@ def main(argv=sys.argv[1:]): # noqa: D103
FORMAT_STR_USE_ENV_VAR = '${name}'
FORMAT_STR_INVOKE_SCRIPT = 'AMENT_CURRENT_PREFIX="{prefix}" ' \
'_ament_prefix_sh_source_script "{script_path}"'
FORMAT_STR_REMOVE_LEADING_SEPARATOR = 'if [ "$(echo -n ${name} | ' \
'head -c 1)" = ":" ]; then export {name}=${{{name}#?}} ; fi'
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = 'if [ "$(echo -n ${name} | ' \
'tail -c 1)" = ":" ]; then export {name}=${{{name}%?}} ; fi'
elif args.primary_extension == 'bat':
Expand All @@ -55,6 +59,8 @@ def main(argv=sys.argv[1:]): # noqa: D103
FORMAT_STR_INVOKE_SCRIPT = \
'call:_ament_prefix_bat_call_script "{script_path}"'
# can't use `if` here since each line is being `call`-ed
FORMAT_STR_REMOVE_LEADING_SEPARATOR = \
'call:_ament_prefix_bat_strip_leading_semicolon "{name}"'
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = \
'call:_ament_prefix_bat_strip_trailing_semicolon "{name}"'
else:
Expand All @@ -75,7 +81,7 @@ def main(argv=sys.argv[1:]): # noqa: D103
):
print(line)

for line in _remove_trailing_separators():
for line in _remove_ending_separators():
print(line)


Expand Down Expand Up @@ -300,6 +306,7 @@ def handle_dsv_types_except_source(type_, remainder, prefix):
else:
assert False
elif type_ in (
DSV_TYPE_APPEND_NON_DUPLICATE,
DSV_TYPE_PREPEND_NON_DUPLICATE,
DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS
):
Expand All @@ -325,6 +332,8 @@ def handle_dsv_types_except_source(type_, remainder, prefix):
f'path: {value}'
commands.append(
FORMAT_STR_COMMENT_LINE.format_map({'comment': comment}))
elif type_ == DSV_TYPE_APPEND_NON_DUPLICATE:
commands += _append_unique_value(env_name, value)
else:
commands += _prepend_unique_value(env_name, value)
else:
Expand All @@ -336,6 +345,28 @@ def handle_dsv_types_except_source(type_, remainder, prefix):
env_state = {}


def _append_unique_value(name, value):
global env_state
if name not in env_state:
if os.environ.get(name):
env_state[name] = set(os.environ[name].split(os.pathsep))
else:
env_state[name] = set()
# 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
extend = FORMAT_STR_USE_ENV_VAR.format_map({'name': name}) + os.pathsep
line = FORMAT_STR_SET_ENV_VAR.format_map(
{'name': name, 'value': extend + value})
if value not in env_state[name]:
env_state[name].add(value)
else:
if not _include_comments():
return []
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
return [line]


def _prepend_unique_value(name, value):
global env_state
if name not in env_state:
Expand All @@ -345,7 +376,7 @@ def _prepend_unique_value(name, value):
env_state[name] = set()
# 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_trailing_separators() will cleanup any unintentional trailing separator
# later _remove_ending_separators() will cleanup any unintentional trailing separator
extend = os.pathsep + FORMAT_STR_USE_ENV_VAR.format_map({'name': name})
line = FORMAT_STR_SET_ENV_VAR.format_map(
{'name': name, 'value': value + extend})
Expand All @@ -358,15 +389,16 @@ def _prepend_unique_value(name, value):
return [line]


def _remove_trailing_separators():
def _remove_ending_separators():
global env_state
commands = []
for name in env_state:
# skip variables that already had values before this script started prepending
if name in os.environ:
continue
commands += [FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map(
{'name': name})]
commands += [
FORMAT_STR_REMOVE_LEADING_SEPARATOR.format_map({'name': name}),
FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map({'name': name})]
return commands


Expand Down
14 changes: 14 additions & 0 deletions ament_package/template/prefix_level/local_setup.bat.in
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ goto:eof
goto:eof


:: strip a leading semicolon from an environment variable if applicable
:: first argument: the environment variable name
:_ament_prefix_bat_strip_leading_semicolon
setlocal enabledelayedexpansion
set "name=%~1"
set "value=!%name%!"
if "%value:~0,1%"==";" set "value=%value:~1%"
:: set result variable in parent scope
endlocal & (
set "%~1=%value%"
)
goto:eof


:: strip a trailing semicolon from an environment variable if applicable
:: first argument: the environment variable name
:_ament_prefix_bat_strip_trailing_semicolon
Expand Down

0 comments on commit 37f9a1f

Please sign in to comment.