From 7f432bca3f9b3d461a3d802cd0f9de283f7fb0f3 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Fri, 31 Dec 2021 13:12:46 +0000 Subject: [PATCH 1/4] RF: Change variable names to make script easier to follow --- share/fsl/sbin/createFSLWrapper | 70 ++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/share/fsl/sbin/createFSLWrapper b/share/fsl/sbin/createFSLWrapper index 5ad8a0b..07dfab0 100755 --- a/share/fsl/sbin/createFSLWrapper +++ b/share/fsl/sbin/createFSLWrapper @@ -48,7 +48,7 @@ # file systems are usually case-sensitive. # # To work around this, and to not accidentally create a link called <Command> -# to <command>, the FSL package post link scripts should only specify +# to <command>, the FSL package post link scripts must only specify # "<Command>_gui", and *not* "<Command>". This script will create a wrapper # script for the appropriate variant ("<Command>_gui" on macOS, or "<Command>" # on Linux). @@ -60,60 +60,66 @@ targets="$@" # Only create wrappers if the FSL_CREATE_WRAPPER_SCRIPTS # environment variable is set -if [ -z "$FSL_CREATE_WRAPPER_SCRIPTS" ]; then +if [ -z "${FSL_CREATE_WRAPPER_SCRIPTS}" ]; then exit 0 fi # Only create wrappers if FSLDIR exists -if [ ! -d "$FSLDIR" ]; then +if [ ! -d "${FSLDIR}" ]; then exit 0 fi # and if FSLDIR == PREFIX -if [ "$FSLDIR" != "$PREFIX" ]; then +if [ "${FSLDIR}" != "${PREFIX}" ]; then exit 0 fi -for script in $targets; do - sourceScript="${PREFIX}/bin/$script" +for targetName in ${targets}; do - # Wrapper script for a FSL TCL GUI - here, we - # remove the _gui suffix if no source file - # exists (in which we are likely running on - # Linux). - if [[ "$script" == *"_gui" ]] && [ ! -f "$sourceScript" ]; then - script=${script/_gui/} - sourceScript="${PREFIX}/bin/$script" - fi + target="${PREFIX}/bin/${targetName}" - targetScript="${FSLDIR}/share/fsl/bin/$script" + # Wrapper script for a FSL TCL GUI - here, + # we remove the _gui suffix if the target + # file does not exist (in which case we are + # likely running on Linux). + if [[ "${targetName}" == *"_gui" ]] && [ ! -f "${target}" ]; then + targetName=${targetName/%_gui} + target=${target/%_gui} + fi - if [ ! -f "$sourceScript" ]; then + # Don't create wrapper scripts for non- + # existent targets (e.g. the post-link.sh + # script for a package may be out-dated, + # and request wrappers for commmands that + # have been removed). + if [ ! -f "${target}" ]; then continue fi + wrapper="${FSLDIR}/share/fsl/bin/${targetName}" + # create share/fsl/bin/ if it doesn't # already exist - if [ ! -e "$FSLDIR/share/fsl/bin" ]; then - mkdir -p "$FSLDIR/share/fsl/bin" + if [ ! -e "${FSLDIR}/share/fsl/bin" ]; then + mkdir -p "${FSLDIR}/share/fsl/bin" fi - # remove target script if it already exists - if [ -e "$targetScript" ]; then - rm "$targetScript" + # remove wrapper script if it already exists + if [ -e "${wrapper}" ]; then + rm "${wrapper}" fi # Figure out whether this is a python # executable or some other type of # executable. - id=$(head -c 1024 "$sourceScript" | grep -e '^#!.*pythonw\?$') + id=$(head -c 1024 "${target}" | grep -e '^#!.*pythonw\?$') # Non-python executable - use # a pass-through script - if [ -z "$id" ]; then - echo "#!/usr/bin/env bash" > "$targetScript" - echo "$FSLDIR/bin/$script "'"$@"' >> "$targetScript" + if [ -z "${id}" ]; then + echo "#!/usr/bin/env bash" > "${wrapper}" + echo "${target} "'"$@"' >> "${wrapper}" else # Python executable - run it via @@ -121,21 +127,21 @@ for script in $targets; do # mode. Under macOS, GUI apps are # invoked with pythonw, so we need # to preserve the interpreter. - if [[ "$id" == *"pythonw" ]]; then + if [[ "${id}" == *"pythonw" ]]; then interp="pythonw" else interp="python" fi - echo "#!/usr/bin/env bash" > "$targetScript" - echo "${FSLDIR}/bin/${interp} -I $sourceScript "'"$@"' >> "$targetScript" + echo "#!/usr/bin/env bash" > "${wrapper}" + echo "${FSLDIR}/bin/${interp} -I ${target} "'"$@"' >> "${wrapper}" fi # Preserve file permissions - if [[ "$OSTYPE" == "darwin"* ]]; then - perms=$(stat -f "%A" "$sourceScript") - chmod ${perms} "$targetScript" + if [[ "${OSTYPE}" == "darwin"* ]]; then + perms=$(stat -f "%A" "${target}") + chmod ${perms} "${wrapper}" else - chmod --reference="$sourceScript" "$targetScript" + chmod --reference="${target}" "${wrapper}" fi done -- GitLab From 5ab211b1bf233746e0aabb1814aad3f34e93c737 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Fri, 31 Dec 2021 17:12:50 +0000 Subject: [PATCH 2/4] ENH: New option in createFSLWrapper to generate wrapper script with different name to executable --- share/fsl/sbin/createFSLWrapper | 75 +++++++++------------------------ share/fsl/sbin/removeFSLWrapper | 29 +++++++++---- 2 files changed, 41 insertions(+), 63 deletions(-) diff --git a/share/fsl/sbin/createFSLWrapper b/share/fsl/sbin/createFSLWrapper index 07dfab0..5093df3 100755 --- a/share/fsl/sbin/createFSLWrapper +++ b/share/fsl/sbin/createFSLWrapper @@ -1,57 +1,15 @@ #!/usr/bin/env bash # # Create wrapper scripts in $FSLDIR/share/fsl/bin/ which invoke commands that -# are installed in $FSLDIR/bin/. +# are installed in $FSLDIR/bin/. Calling this script like: # -# This script is used to create isolated versions of all executables provided -# by FSL projects, so they can be added to the user $PATH without any other -# executables that are installed into the FSL conda environment (for example, -# python, pip, tcl, etc). +# createFSLWrapper command1 command2 command3 # -# This script is intended to be called by the post-link.sh script of the conda -# recipe for each FSL project that provides executable commands. +# will cause wrapper scripts to be created in $FSLDIR/share/fsl/bin/, which +# call the commands of the same name in $FSLDIR/bin/, i.e.: # -# This script should only be invoked when FSL is being installed via the -# fslinstaller script - it is not intended to be used when individual FSL -# projects are explicitly installed into a custom conda environment. -# -# The fslinstaller script should ensure that the FSLDIR and -# FSL_CREATE_WRAPPER_SCRIPTS variables are set appropriately before creating -# the FSL conda environment. -# -# Wrapper scripts will only be created if the following conditions are met: -# -# - The $FSLDIR and $PREFIX environment variables are set, and -# are equivalent -# - The $FSL_CREATE_WRAPPER_SCRIPTS environment variable is set and is not -# empty. -# -# Wrapper scripts, and not sym-links, are used to avoid a couple of potential -# problems: -# -# - We need python executables to exclusively use the libraries installed in -# the FSL conda environment. Users may have other Python environments -# activated, and/or libraries installed into a local site-packages -# directory. So we need to invoke the python interpreter in isolated mode, -# with the -I flag: -# -# https://docs.python.org/3/using/cmdline.html#id2 -# -# - There is no guarantee that a shell supports shebang lines longer than 127 -# characters. Depending on where FSL is installed, it may not be possible -# to have a shebang line pointing to $FSLDIR/bin/python which does not -# exceed 127 characters. -# -# Wrapper scripts are created for *all* FSL commands, including FSL TCL GUI -# commands (e.g. "fsl", "Flirt", "Flirt_gui", etc). FSL TCL GUIs are called -# (e.g.) "<Command>" om Linux, but "<Command>_gui" on macOS, because macOS -# file systems are usually case-sensitive. -# -# To work around this, and to not accidentally create a link called <Command> -# to <command>, the FSL package post link scripts must only specify -# "<Command>_gui", and *not* "<Command>". This script will create a wrapper -# script for the appropriate variant ("<Command>_gui" on macOS, or "<Command>" -# on Linux). +# $FSLDIR/share/fsl/bin/command1 calls $FSLDIR/bin/command1 +# $FSLDIR/share/fsl/bin/command2 calls $FSLDIR/bin/command2 # Names of all executables for which wrapper # scripts are to be created are passed as @@ -75,16 +33,27 @@ if [ "${FSLDIR}" != "${PREFIX}" ]; then fi -for targetName in ${targets}; do +for target in ${targets}; do + + # A wrapper script with a different + # name to the target can be created + # by passing "targetName=wrapperName" + if [[ "${target}" == *"="* ]]; then + wrapper=${target#*=} + target=${target%=*} + else + wrapper=${target} + fi - target="${PREFIX}/bin/${targetName}" + target="${FSLDIR}/bin/${target}" + wrapper="${FSLDIR}/share/fsl/bin/${wrapper}" # Wrapper script for a FSL TCL GUI - here, # we remove the _gui suffix if the target # file does not exist (in which case we are # likely running on Linux). - if [[ "${targetName}" == *"_gui" ]] && [ ! -f "${target}" ]; then - targetName=${targetName/%_gui} + if [[ "${target}" == *"_gui" ]] && [ ! -f "${target}" ]; then + wrapper=${wrapper/%_gui} target=${target/%_gui} fi @@ -97,8 +66,6 @@ for targetName in ${targets}; do continue fi - wrapper="${FSLDIR}/share/fsl/bin/${targetName}" - # create share/fsl/bin/ if it doesn't # already exist if [ ! -e "${FSLDIR}/share/fsl/bin" ]; then diff --git a/share/fsl/sbin/removeFSLWrapper b/share/fsl/sbin/removeFSLWrapper index 8b42934..6e122d7 100755 --- a/share/fsl/sbin/removeFSLWrapper +++ b/share/fsl/sbin/removeFSLWrapper @@ -1,7 +1,7 @@ #!/usr/bin/env bash # # Remove wrapper script/links in $FSLDIR/share/fsl/bin/ which invoke commands -# that are installed in $FSLDIR/bin/. See createFSLWrapper for more +# that are installed in $FSLDIR/bin/. See createFSLWrapper for more # information. # # This script is intended to be called by the pre-unlink.sh script of the @@ -19,25 +19,36 @@ targets="$@" # delete any wrapper scripts that exist. # Only remove wrappers if FSLDIR exists -if [ ! -d "$FSLDIR" ]; then +if [ ! -d "${FSLDIR}" ]; then exit 0 fi # and if FSLDIR == PREFIX -if [ "$FSLDIR" != "$PREFIX" ]; then +if [ "${FSLDIR}" != "${PREFIX}" ]; then exit 0 fi # Only remove if scripts are in subdirectory of FSLDIR -for script in $targets; do - targetScript="${FSLDIR}/share/fsl/bin/$script" +for target in ${targets}; do + + # A wrapper script with a different + # name to the target can be created + # by passing "targetName=wrapperName" + if [[ "${target}" == *"="* ]]; then + wrapper=${target#*=} + target=${target%=*} + else + wrapper=${target} + fi + + wrapper="${FSLDIR}/share/fsl/bin/${wrapper}" # See comment about FSL GUIs in post-link.sh - if [[ "$targetScript" == *"_gui" ]] && [ ! -f "$targetScript" ]; then - targetScript=${targetScript/_gui/} + if [[ "${target}" == *"_gui" ]] && [ ! -f "${wrapper}" ]; then + wrapper=${wrapper/%_gui} fi - if [ -f "$targetScript" ]; then - rm "$targetScript" + if [ -f "${wrapper}" ]; then + rm "${wrapper}" fi done -- GitLab From eeb2580ca43eeb40bb2143cc13c4bb090015f224 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Fri, 31 Dec 2021 17:13:20 +0000 Subject: [PATCH 3/4] TEST: Test createFSLWrapper rename capability --- tests/test_create_remove_wrapper.py | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test_create_remove_wrapper.py b/tests/test_create_remove_wrapper.py index b2abcce..624fd5e 100755 --- a/tests/test_create_remove_wrapper.py +++ b/tests/test_create_remove_wrapper.py @@ -305,6 +305,46 @@ def test_create_wrappers_no_handle_gui_wrappers(): assert not op.exists(wrapper) +def test_create_wrappers_rename(): + """Tests the renaming functionality in createFSLWrapper. If + $FSLDIR/bin/script exists, a wrapper with a different name + (e.g. $FSLDIR/share/fsl/bin/renamed_script) can be created by passing + "script=renamed_script". + """ + + # Keys are passed to createFSLWrapper, values + # are wrappers that should be created + scripts = { + 'script1=renamed_script1' : 'renamed_script1', + 'script2=renamed_script2' : 'renamed_script2', + 'script3_gui=renamed_script3_gui' : 'renamed_script3_gui', + 'script4_gui=renamed_script4' : 'renamed_script4' + } + + with temp_fsldir() as (fsldir, wrapperdir): + for script in scripts.keys(): + target = script.split('=')[0] + with open(target, 'wt') as f: + touch(op.join(fsldir, 'bin', target)) + + for wrappers in it.permutations(scripts.keys()): + args = ' '.join(wrappers) + run(f'{CREATE_WRAPPER} {args}') + + for arg in wrappers: + target = arg.split('=')[0] + wrapper = op.join(wrapperdir, scripts[arg]) + + assert op.exists(wrapper) + assert get_called_command(wrapper) == target + + run(f'{REMOVE_WRAPPER} {args}') + for arg in wrappers: + target = scripts[arg] + wrapper = op.join(wrapperdir, target) + assert not op.exists(wrapper) + + if __name__ == '__main__': # base dir can be speecified on command line if len(sys.argv) > 1: -- GitLab From 1393d89493cf2589e6d9d34f910721fa38db7fda Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Fri, 31 Dec 2021 17:14:24 +0000 Subject: [PATCH 4/4] DOC: changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b86a7a..58f02a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # FSL base project changelog +## 2112.6 (Thursday 31st December 2021) + +* The `createFSLWrapper` script nowe has the ability to generate a wrapper + script with a name different to the called executable. + ## 2112.5 (Thursday 30th December 2021) -- GitLab