From 54ff09f9eb8d35ca914376ae872cc7e60093547b Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 11:51:14 -0800 Subject: [PATCH] Add support for appending to environment variables (#130) (#137) 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 (cherry picked from commit 37f9a1f5e19a2513051ece437c3ef14a0cbaf836) Co-authored-by: Scott K Logan --- .../template/package_level/local_setup.bat.in | 33 +++++++++++- .../template/package_level/local_setup.sh.in | 51 +++++++++++++++++++ .../prefix_level/_local_setup_util.py | 42 +++++++++++++-- .../template/prefix_level/local_setup.bat.in | 14 +++++ 4 files changed, 134 insertions(+), 6 deletions(-) diff --git a/ament_package/template/package_level/local_setup.bat.in b/ament_package/template/package_level/local_setup.bat.in index 9b83676..4bb2015 100644 --- a/ament_package/template/package_level/local_setup.bat.in +++ b/ament_package/template/package_level/local_setup.bat.in @@ -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 @@ -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 diff --git a/ament_package/template/package_level/local_setup.sh.in b/ament_package/template/package_level/local_setup.sh.in index 28e12cf..60a8b16 100644 --- a/ament_package/template/package_level/local_setup.sh.in +++ b/ament_package/template/package_level/local_setup.sh.in @@ -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() { diff --git a/ament_package/template/prefix_level/_local_setup_util.py b/ament_package/template/prefix_level/_local_setup_util.py index fd914bd..ede66c7 100644 --- a/ament_package/template/prefix_level/_local_setup_util.py +++ b/ament_package/template/prefix_level/_local_setup_util.py @@ -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' @@ -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( @@ -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': @@ -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: @@ -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) @@ -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 ): @@ -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: @@ -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: @@ -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}) @@ -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 diff --git a/ament_package/template/prefix_level/local_setup.bat.in b/ament_package/template/prefix_level/local_setup.bat.in index f2727db..2297042 100644 --- a/ament_package/template/prefix_level/local_setup.bat.in +++ b/ament_package/template/prefix_level/local_setup.bat.in @@ -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