2012-12-13

Linux: Bash generic script to switch versions (like alternatives and Gentoo's eselect)

I've made a switch script.

Usage

1.$ switch
2.$ switch maven 2.2.1
3.$ mvn -version
4.$ switch maven 2.1.0
5.$ mvn -version

Installation

It uses your ~/sw/tools/.links, so update your PATH.

1.export PATH=~/sw/tools/.links:$PATH

Then (optionally):

1.$ /mnt/jqa/sw/tools/switch.sh install
2.Creating ~/sw/tools/.links/switch -> /mnt/jqa/sw/tools/switch.sh

Download

Download here.

Script's code

001.#####################################################################################################
002.#
003.#  This script creates switches between the versions of various tools,
004.#  found in /mnt/jqa/sw/tools/ (curently hard-coded).
005.#
006.#  Usage:
007.#    $ switch maven 2.1.0
008.#    $ mvn ...
009.#
010.#  Installation:
011.#   * Set PATH to begin with ~/sw/tools/.links (in ~/.bashrc)
012.#
013.#  Tools directory structure:
014.#   * .../<tool_name>/
015.#     * <tool_version>/
016.#     * <tool_version2>/
017.#     * onSwitch.sh
018.#     * onRun.sh
019.#
020.#  Callback scripts:
021.#
022.#   * onSwitch.sh - called when the version switch is performed.
023.#     * Called using:   . onSwitch.sh <tool_name> <tool_version>
024.#
025.#   * onRun.sh - if present, all tool's runnables will be called through a script,
026.#                which will be re-created each time the versions are switched:
027.#
028.#          TOOL_NAME=<tool_name>    # Few variables are set at the top of the script.
029.#          TOOL_VERSION=<...>       # 1.2.3
030.#          TOOL_HOME=<...>          # Tool home dir - i.e., the dir particular version.
031.#          TOOL_RUNNABLE_PATH=<...> # Path to the runnable to be called.
032.#
033.#          <content of onRun.sh>    # The content is simply pasted here.
034.#          <tool_runnable> $@       # Calls the current version of the tool runnable.
035.#
036.#  Todo:
037.#   * Upon switch, remove links created with previous switch.
038.#     * All that belong to the tools/<tool_name> dir (parse the variables at the top of the scripts)
039.#
040.#  History:
041.#  2009-12-22:
042.#   * Runnables are now searched automatically in TOOL_HOME/bin if there's no runnables.txt.
043.#   * Softlinks to executable files also count as runnables.
044.#   * Home dir of this script is detected automatically.
045.#   * Meta-dirs now start with a dot (.links, .homes, .template).
046.#
047.#
048.#####################################################################################################
049. 
050. 
051.##
052.##  @param  $1  Tool name
053.##  @param  $2  Tool version
054.##  @param  $3  Tool runnable path
055.##  @param  $4  TOOL_HOME - path to the home dir of the selected version of the tool.
056.##  @param  $5  ON_RUN - a script to execute before the runnable is run.
057.##
058.function createRunnableScript {
059. 
060.        TOOL_RUNNABLE_PATH=$3
061.        TOOL_HOME=$4
062.        ON_RUN=$5
063. 
064.        TOOL_RUNNABLE_NAME=`basename $TOOL_RUNNABLE_PATH`;
065.        MY_LINK=~/sw/tools/.links/$TOOL_RUNNABLE_NAME
066.        if [ -e "$MY_LINK" ] ; then rm $MY_LINK; fi
067.        if [ -z "$ON_RUN" ] ; then
068.                echo "Creating link $MY_LINK -> $TOOL_RUNNABLE_PATH"
069.                ln -s  $TOOL_RUNNABLE_PATH  $MY_LINK
070.        else
071.                echo "Creating bash script: $MY_LINK"
072.                echo "TOOL_NAME=$1" &gt; $MY_LINK;
073.                echo "TOOL_VERSION=$2" &gt;&gt; $MY_LINK;
074.                echo "TOOL_HOME=$TOOL_HOME" &gt;&gt; $MY_LINK;
075.                echo "TOOL_RUNNABLE_PATH=$TOOL_RUNNABLE_PATH" &gt;&gt; $MY_LINK;
076.                cat $ON_RUN &gt;&gt; $MY_LINK;
077.                echo "" &gt;&gt; $MY_LINK
078.                echo "exec $TOOL_RUNNABLE_PATH \"\$@\"" &gt;&gt; $MY_LINK;
079.        fi
080.        chmod +x $MY_LINK
081.}
082. 
083. 
084. 
085.##  Return value.
086.RET=0
087. 
088. 
089.        ##  Determine this script's location ("Tools" home dir).
090. 
091.        #TOOLS="/home/ondra/sw/tools"
092. 
093.        #scriptPath=$(cd ${0%/*} && echo $PWD/${0##*/})
094.        scriptPath="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"
095.        # For the case when called through a symlink (eg. sw/tools/.links/switch -> ../switch.sh).
096.        scriptPath=`readlink -f "$scriptPath"`
097. 
098.        TOOLS=`dirname "$scriptPath"`
099. 
100. 
101. 
102.##  Install - create the .links dir and a link to the switch.sh script.
103.##  Assumes that user will put ~/sw/tools/.links at the beginning of his $PATH.
104.if [ "$1" == "install" ] ; then
105.        if [ ! -x ~/sw/tools/.links/switch ] ; then
106.                echo "Creating ~/sw/tools/.links/switch -> $scriptPath"
107.                mkdir -p ~/sw/tools/.links
108.                ln -s  $scriptPath ~/sw/tools/.links/switch
109.        else
110.                echo "~/sw/tools/.links/switch already exists."
111.        fi
112.        exit;
113.fi
114. 
115. 
116. 
117.while true; do
118. 
119. 
120.        if [ "on" == "$1" ] ; then
121.                ## No way to export a variable without sourcing this script :(
122.                export PATH=~/sw/tools/.links:$PATH
123.        fi
124. 
125.        ##  No arguments: List available tools and versions.
126.        if [ -z "$1" -o -z "$2" ] ; then
127.                echo "    Usage:   switch <tool> <ver>";
128.                echo "    Available tools and versions:"
129.                for TOOL in `ls -1 --ignore=switch.* --ignore=.* --ignore=_* $TOOLS`; do
130.                        if [ ! -d "$TOOLS/$TOOL" ] ; then continue; fi
131.                        #echo "      $TOOL `ls --ignore=*.path $TOOLS/$TOOL`";
132.                        echo "      "$(echo "$TOOL `find -L $TOOLS/$TOOL/ -mindepth 1 -maxdepth 1 -type d | sed 's#.*/##'`");
133.                        #tree -diL 1
134.                        #ls -l | grep ^d | awk '{print $9}'
135.                done
136.                break;
137.        fi
138. 
139.        ##  Has to be sourced for it sets variables into the environment (like M2_HOME).
140.        if [ "$0" == "switch.sh" ] ; then
141.                echo "This file (switch.sh) has to be source'd  ('. switch.sh').";
142.                exit 666;
143.        fi
144. 
145. 
146. 
147.        ##  Tool's root dir (contains dirs with concrete versions).
148.        TOOL_DIR="$TOOLS/$1"
149.        if [ ! -d "$TOOL_DIR" ] ; then echo "Unknown tool: $1"; RET=1; break; fi
150. 
151.        ##  Particular version's dir.
152.        TOOL_HOME="$TOOL_DIR/$2"
153.        if [ ! -d "$TOOL_HOME" ] ; then echo "$1 doesn't have a version: $2"; RET=2; break; fi
154. 
155. 
156.        mkdir -p ~/sw/tools/.links
157.        mkdir -p ~/sw/tools/.homes
158. 
159. 
160.        ##  Commands to perform before running the tool (each time).
161.        if [ -x "$TOOL_DIR/onRun.sh" ] ; then
162.                ON_RUN=$TOOL_DIR/onRun.sh;
163.        fi
164. 
165. 
166.        ##  Create the HOME links.
167.        echo "Creating link ~/sw/tools/.homes/$1 -> $TOOL_HOME"
168.        rm ~/sw/tools/.homes/$1
169.        ln -s $TOOL_HOME ~/sw/tools/.homes/$1
170. 
171. 
172.        ##  Commands to run upon version switching.
173.        if [ -x "$TOOL_DIR/onSwitch.sh" ] ; then
174.                echo "Running '$TOOL_DIR/onSwitch.sh $TOOL_HOME'...";
175.                $TOOL_DIR/onSwitch.sh $TOOL_HOME;
176.        fi
177. 
178. 
179. 
180. 
181.        ##  Tool's runnable from the path.
182.        ##  Check the symlink existence.
183.        if [ ! -h $TOOL_DIR/runnable.path ] ; then
184.                #echo "Every tool has to have an (invalid) symlink with the path from tool's HOME to the executable."; RET=3; break;
185.                true;
186.        else
187.                TOOL_RUNNABLE_PATH=$TOOL_HOME/`readlink $TOOL_DIR/runnable.path`
188.                if [ ! -e "$TOOL_RUNNABLE_PATH" ] ; then echo "Non-existent runnable: $TOOL_RUNNABLE_PATH"; RET=4; break; fi
189.                if [ ! -x "$TOOL_RUNNABLE_PATH" ] ; then echo "Non-executable runnable: $TOOL_RUNNABLE_PATH"; RET=5; break; fi
190. 
191.                ##  Create a link to the runnable in ~/sw/tools/.links/, named like the tool name.
192.                createRunnableScript $1 $2 $TOOL_RUNNABLE_PATH $TOOL_HOME $ON_RUN
193.        fi
194. 
195. 
196. 
197.        if [ -x "$TOOL_DIR/runnables.txt" ] ; then
198.                ##   Link runnables listed in a file /sw/tools/<tool>/runnables.txt .
199.                ##   TODO: Find automatically all executables from the tool's dir.
200.                ##         Upon creation of those, remove links pointing to the particular tool's dir.
201.                for RUNNABLE_SUBPATH in `cat $TOOL_DIR/runnables.txt`; do
202.                        TOOL_RUNNABLE_PATH=$TOOL_HOME/$RUNNABLE_SUBPATH;
203.                        if [ ! -e "$TOOL_RUNNABLE_PATH" ] ; then echo "Non-existent runnable: $TOOL_RUNNABLE_PATH"; RET=4; break 2; fi
204.                        if [ ! -x "$TOOL_RUNNABLE_PATH" ] ; then echo "Non-executable runnable: $TOOL_RUNNABLE_PATH"; RET=5; break 2; fi
205.                done
206. 
207.                for RUNNABLE_SUBPATH in `cat $TOOL_DIR/runnables.txt`; do
208.                        TOOL_RUNNABLE_PATH=$TOOL_HOME/$RUNNABLE_SUBPATH;
209.                        createRunnableScript $1 $2 $TOOL_RUNNABLE_PATH $TOOL_HOME $ON_RUN
210.                done
211.        else
212.                ##   runnables.txt does not exist, scan the dir for executable files and links.
213.                #for RUNNABLE_SUBPATH in `ls -l $TOOL_HOME/bin | grep -e ^[-l]..x | cut  -b47- | cut -d' ' -f1`; do
214.                        #TOOL_RUNNABLE_PATH=$TOOL_HOME/bin/$RUNNABLE_SUBPATH;
215.                for TOOL_RUNNABLE_PATH in $TOOL_HOME/bin/* ; do if [ -x "$TOOL_RUNNABLE_PATH" -a -f "$TOOL_RUNNABLE_PATH" ] ; then
216.                        createRunnableScript $1 $2 $TOOL_RUNNABLE_PATH $TOOL_HOME $ON_RUN
217.                fi ; done
218.        fi
219. 
220.break;
221.done # while true
222. 
223.##  Clear bash's cache.
224.hash -r
225. 
226. 
227.##  If called without `source`, return an exit code.
228.if [ "$0" == "switch.sh" ] ; then exit $RET; fi

0