Today, depending on the plugin being used, the snapcraft CLI may generate a wrapper per app containing various environment variables, sourcing scripts, etc. before actually calling the command defined. This can look pretty confusing and ugly if you’re not expecting it.
Proposal
Rather than have the snapcraft CLI magically create a wrapper per app, it should install new scripts into the snap and use the command-chain proposal. For example:
This, in combination with the environment keyword, would completely eliminate wrappers and allow snap run --shell to provide an environment truly representative of the app.
In many cases, such as this one, the wrapper consists entirely of environment variables, which nowadays should be using the environment property (although hooks don’t support that yet). However, depending on the plugins used, the wrappers can be far more complex, well beyond just exporting variables. Avert your eyes:
#!/bin/sh
export PATH="$SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu"
export ROS_MASTER_URI=http://localhost:11311
export ROS_HOME=${SNAP_USER_DATA:-/tmp}/ros
export LC_ALL=C.UTF-8
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu
export PYTHONPATH=$SNAP/usr/lib/python2.7/dist-packages${PYTHONPATH:+:$PYTHONPATH}
export PATH=$PATH:$SNAP/usr/bin
# Shell quote arbitrary string by replacing every occurrence of '
# with '\'', then put ' at the beginning and end of the string.
# Prepare yourself, fun regex ahead.
quote()
{
for i; do
printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"
done
echo " "
}
BACKUP_ARGS=$(quote "$@")
set --
if [ -f $SNAP/opt/ros/kinetic/setup.sh ]; then
_CATKIN_SETUP_DIR=$SNAP/opt/ros/kinetic . $SNAP/opt/ros/kinetic/setup.sh
fi
eval "set -- $BACKUP_ARGS"
export LD_LIBRARY_PATH="$SNAP/opt/ros/kinetic/lib:$SNAP/usr/lib:$SNAP/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH
exec "roslaunch" "edukit_bot" "edukit_bot.launch" "$@"
The more plugins involved, the nastier it gets. This proposal is to stop dumping everything into a nasty wrapper, and simply provide an executable instead, telling snapd that it must run before the app by using the command-chain keyword.
This comes back to the templates proposal as well: we want to keep templates solely to generating YAML, not throwing more shell code in an opaque, already-nasty wrapper. This empowers it to simply add a command to the chain.
The template will do whatever it needs, if it needs a command because it does more than setup an environment variable, it will use that; if not, it will just setup environment appropriately. The only gotcha with environment is that it is a dict, and each environment entry has its own semantics on how to cascade them and we are trying to get out of the Harry Potter world with snapcraft and leave the Ministry of Magic to that realm only.