#!/bin/bash # # headless wfdb-swig-matlab installer for *nix systems # # # # BASE_URL="" MATLAB="" TEMP_JAR_DIR="" WSM_TEMP_DIR=~/.wfdb-swig-matlab-tmp WSM_FINAL_DIR=~/.wfdb-swig-matlab WSM_VERSION=0.0.1 # # # CURL=$(which curl 2>/dev/null || echo) JAR=$(which jar 2>/dev/null || echo) UUIDGEN=$(which uuidgen 2>/dev/null || echo) WGET=$(which wget 2>/dev/null || echo) # # # INSTALL_GLOBALLY="" JAR_NAME="" PRINT_HELP="" SOURCE_PATH=$(pwd) SU_METHOD=sudo # # # detailed_usage_msg() { echo "Try \`$0 -h' to see detailed usage." 1>&2 } # # $1 is the location of a matlab binary (may be a symlink) # # if OK, return 0, and return the result into stdout; # on error, return 1, and return the error string into stdout # find_default_matlab_path() { matlab_bin="$1" if [ -z "$matlab_bin" ] then echo "*** Error: No default MATLAB found." 1>&2 return 1 fi matlab=$("$matlab_bin" -e | sed -n 's/^MATLAB=\(.*\)$/\1/p') if [ -z "$matlab" ] then echo "*** Error: No MATLAB env. var. for default MATLAB." 1>&2 return 1 fi echo "$matlab" return 0 } # # $1 is the url, # $2 is the location to put the file # http_get() { if [ ! -z "$WGET" ] then wget -O "$2" "$1" elif [ ! -z "$CURL" ] then curl -o "$2" "$1" else echo "*** Error: neither wget nor curl available; can't get $1." 1>&2 return 1 fi } # # $1 is the OS name # $2 is the arch name # is_valid_kernel_and_arch() { if [ "$#" -ne "2" ] then echo "*** Error: is_valid_kernel_and_arch() used incorrectly;" echo " expected 2 args., but passed $#." echo " Exiting." exit 1 fi case "$1" in "Linux" ) case "$2" in "i386" ) return 0 ;; "amd64" ) return 0 ;; * ) echo "*** Error: Unsupported architecture for operating system $1: $2" 1>&2 return 1 ;; esac ;; "Darwin" ) case "$2" in "ppc" ) return 0 ;; * ) echo "*** Error: Unsupported architecture for operating system $1: $2" 1>&2 return 1 ;; esac ;; * ) echo "*** Error: Unsupported OS: $1" 1>&2 return 1 ;; esac } # # $1 is the kernel name as printed by uname # the result is what i've been calling it elsewhere # kernel_to_os() { case "$1" in "Linux" ) echo "linux" return 0 ;; "Darwin" ) echo "macosx" return 0 ;; * ) echo "*** Error: Unknown kernel name: $1" 1>&2 return 1 esac } # # # make_uuid() { if [ ! -z "$UUIDGEN" ] then "$UUIDGEN" else echo "00000000-0000-0000-0000-000000000000" fi } # # # on_err_exit() { echo "Exiting." exit 1 } # # FIXME: should use an associative array for the USED_? vars. # parse_args() { local USED_J="" local USED_M="" local USED_P="" local USED_S="" while [ "$#" -ne "0" ] do case "$1" in # FIXME: re-launch as root, or at least warn about not being root "-g" ) INSTALL_GLOBALLY=1 ;; "-h" ) PRINT_HELP=true ;; "-j" ) shift if [ ! -z "$USED_J" ] then echo "*** Error: -j used more than once." 1>&2 detailed_usage_msg return 1 elif [ -z "$1" ] then echo "*** Error: -j used without a JAR_NAME." 1>&2 detailed_usage_msg return 1 else JAR_NAME="$1" USED_J=1 fi ;; "-m" ) shift if [ ! -z "$USED_M" ] then echo "*** Error: -m used more than once." 1>&2 detailed_usage_msg return 1 elif [ -z "$1" ] then echo "*** Error: -m used without a MATLAB_PATH." 1>&2 detailed_usage_msg return 1 else MATLAB="$1" USED_M=1 fi ;; "-p" ) shift if [ ! -z "$USED_P" ] then echo "*** Error: -p used more than once." 1>&2 detailed_usage_msg return 1 elif [ -z "$1" ] then echo "*** Error: -p used without a PATH." 1>&2 detailed_usage_msg return 1 else SOURCE_PATH="$1" USED_P=1 fi ;; "-s" ) shift if [ ! -z "$USED_S" ] then echo "*** Error: -s used more than once." 1>&2 detailed_usage_msg return 1 elif [ -z "$1" ] then echo "*** Error: -s used without a METHOD." 1>&2 detailed_usage_msg return 1 else if [ "$1" != "sudo" ] && [ "$1" != "su" ] then echo "*** Error: -s used with invalid method." 1>&2 detailed_usage_msg return 1 else SU_METHOD="$1" USED_S=1 fi fi ;; * ) echo "*** Error: invalid argument: $1" 1>&2 detailed_usage_msg return 1 ;; esac shift done } # # # print_help() { echo "Usage: $0 [OPTION] ..." echo "Install WFDB Tools for MATLAB." echo echo "All arguments are optional:" echo " -g install globally, i.e. in one location" echo " accessible to all users; must be run" echo " as superuser (default: no)" echo " -h print this usage information" echo " -j JAR_NAME use a jar program called JAR_NAME;" echo " on some systems, it is called \"gjar\" or" echo " \"fastjar\" (default: \"jar\")" echo " -m MATLAB_PATH use the Matlab installation in MATLAB_PATH" echo " (default: first executable matlab in your \$PATH)" echo " -p PATH install from the source path PATH," echo " which is either a directory in the" echo " local file system or a URL starting" echo " with \"http://\" (default: current working dir.)" echo " -s METHOD if superuser access is necessary, use" echo " su if METHOD is \"su\" and sudo if \"sudo\"" echo " (default: \"sudo\")" return 0 } # # $1 should be the prompt to display; # $2 should be a string of characters that don't need # to be escaped in a regular expression # # returns result into $RESULT # # FIXMEFIXME: have DEFAULTS!!! # FIXME: change this to use stdout # read_char_prompt() { if [ "$#" -ne "2" ] then echo "*** Error: read_char_prompt() used incorrectly;" echo " expected 2 args., but passed $#." echo " Exiting." exit 1 fi prompt="$1" chars_allowed="$2" while [ true ] do echo -n "$prompt [$chars_allowed] " read v v=$(echo "$v" | sed -n "/^[$chars_allowed]\$/p") if [ ! -z "$v" ] then RESULT="$v" return 0 fi done } # # $1 should be the prompt to display; # $2 should be the default choice # # returns result into $RESULT # does not allow empty string to be returned # # FIXME: change this to use stdout # read_string_prompt() { if [ "$#" -ne "2" ] then echo "*** Error: read_string_prompt() used incorrectly;" echo " expected 2 args., but passed $#." echo " Exiting." exit 1 fi prompt="$1" default="$2" while [ true ] do echo -n "$prompt [default: $default] " read v if [ -z "$v" ] then v="$default" fi if [ ! -z "$v" ] then RESULT="$v" return 0 fi done } # # # run_su() { case "$SU_METHOD" in "su" ) su -c "$*" return "$?" ;; "sudo" ) sudo $* return "$?" ;; esac } # # if any individual command fails, exit # trap on_err_exit ERR # # # parse_args $* if [ ! -z "$PRINT_HELP" ] then print_help exit 0 fi # # prompt for final dir. if installing globally # if [ ! -z "$INSTALL_GLOBALLY" ] then if [ $(id -u) -ne "0" ] then echo "*** You've chosen global installation; please restart $0 as superuser." exit 1 fi read_string_prompt "Where would you like to put the wfdb-swig-matlab directory?" \ "/usr/local/wfdb-swig-matlab" WSM_FINAL_DIR=$RESULT echo "OK, I'll install to $WSM_FINAL_DIR." fi # # # if [ ! -z "$JAR_NAME" ] then JAR=$(which "$JAR_NAME" 2>/dev/null || echo) fi if [ -z "$JAR" ] then echo "*** Error: No jar program found. Please put it in your path," echo " or use -j to specify an alternate name (e.g. gjar or fastjar.)" exit 1 fi # # find matlab # if [ -z "$MATLAB" ] then echo echo "Looking for MATLAB ..." MATLABBIN=$(which matlab 2>/dev/null || echo) MATLAB=$(find_default_matlab_path "$MATLABBIN") echo "Found MATLAB in $MATLAB" else MATLABBIN="$MATLAB/bin/matlab" if [ ! -e "$MATLABBIN" ] then echo "*** Error: I expected a Matlab executable at $MATLABBIN, but it wasn't there." 1>&2 exit 1 fi fi # FIXME: is this strictly necessary? for pf in classpath.txt librarypath.txt do if [ ! -e "$MATLAB/toolbox/local/$pf" ] then echo "*** Error: I expected $MATLAB/toolbox/local/$pf to exist, but it doesn't." 1>&2 exit 1 fi done # # get matlab version and jvm arch. # FIXME: this is ever so slightly brittle; i preferred keeping the # version and arch. on separate lines, but matlab is not # consistent about it what it prints before/after my fprintf() # echo "Asking MATLAB for version and JVM arch. information ..." VERSION_AND_ARCH=$("$MATLABBIN" -nodesktop -nodisplay -nosplash \ -r "nl=['\\','n'];fprintf(1,['%s vvvvv %s',nl], \ version, \ char(java.lang.System.getProperty('os.arch')));exit;"\ | grep ".* vvvvv .*") OLDIFS="$IFS" IFS='' MATLAB_VERSION=$(echo "$VERSION_AND_ARCH" | sed -n -e 's/\(.*\) vvvvv \(.*\)/\1/p') ARCH=$(echo "$VERSION_AND_ARCH" | sed -n -e 's/\(.*\) vvvvv \(.*\)/\2/p') IFS="$OLDIFS" echo "This is MATLAB version $MATLAB_VERSION, with JVM arch. $ARCH" # # # KERNEL=$(uname -s) is_valid_kernel_and_arch "$KERNEL" "$ARCH" OS=$(kernel_to_os "$KERNEL") # # decide on a temp. dir. # while [ -e "$WSM_TEMP_DIR" ] do echo # FIXME: break this up into separate lines read_char_prompt \ "I want to use $WSM_TEMP_DIR but it already exists; can I remove it?" \ "yn" if [ "$RESULT" = "y" ] then { rm -rf "$WSM_TEMP_DIR"; } || \ { echo "Unable to remove $WSM_TEMP_DIR -- exiting."; exit 1; } else # "$RESULT" = "n" read_string_prompt \ "OK, what should I use as a temp. directory?" \ "" WSM_TEMP_DIR="$RESULT" fi done mkdir "$WSM_TEMP_DIR" # # verify that the given path contains the right files # if [[ "$SOURCE_PATH" == "http://"* ]] then BASE_URL="$SOURCE_PATH" TEMP_JAR_DIR="$WSM_TEMP_DIR/tmp" SOURCE_PATH="$TEMP_JAR_DIR" mkdir "$SOURCE_PATH" http_get "$BASE_URL/wfdb-swig.jar" "$SOURCE_PATH/wfdb-swig.jar" http_get "$BASE_URL/wsm-matlab-code.jar" "$SOURCE_PATH/wsm-matlab-code.jar" http_get "$BASE_URL/wfdb-swig-matlab-$OS.jar" \ "$SOURCE_PATH/wfdb-swig-matlab-$OS.jar" http_get "$BASE_URL/wfdb-nativelibs-$OS-$ARCH.jar" \ "$SOURCE_PATH/wfdb-nativelibs-$OS-$ARCH.jar" fi # # check that all the files are there # FILES_MISSING="" for f in wfdb-swig.jar wsm-matlab-code.jar \ "wfdb-swig-matlab-$OS.jar" "wfdb-nativelibs-$OS-$ARCH.jar" do if [ ! -e "$SOURCE_PATH/$f" ] then echo "*** Error: $SOURCE_PATH/$f should exist, but it doesn't." 1>&2 # if [[ "$SOURCE_PATH" != "http://"* ]] # then # echo " (Did you not run make first?)" 1>&2 # fi FILES_MISSING=1 fi done if [ ! -z "$FILES_MISSING" ] then if [[ "$SOURCE_PATH" == "http://"* ]] then exit 1 else echo read_char_prompt "Should I try running make in ${SOURCE_PATH}?" "yn" if [ "$RESULT" = "n" ] then echo "OK, giving up." exit 1 fi (pushd $(pwd) >/dev/null && \ cd "$SOURCE_PATH" && \ make && \ popd >/dev/null) # FIXME: a bit of redundancy here, with the above check for f in wfdb-swig.jar wsm-matlab-code.jar \ "wfdb-swig-matlab-$OS.jar" "wfdb-nativelibs-$OS-$ARCH.jar" do if [ ! -e "$SOURCE_PATH/$f" ] then echo "*** Error: $SOURCE_PATH/$f still doesn't exist;" 1>&2 echo " something has gone very wrong." 1>&2 exit 1 fi done fi fi # # copy the files into ~/.wfdb-swig-matlab # echo echo "OK, copying files into temp. dir. ${WSM_TEMP_DIR} ..." mkdir "$WSM_TEMP_DIR/$WSM_VERSION" mkdir "$WSM_TEMP_DIR/$WSM_VERSION/util" mkdir "$WSM_TEMP_DIR/$WSM_VERSION/lib-$ARCH" # unjar (pushd $(pwd) >/dev/null && \ cd "$WSM_TEMP_DIR/$WSM_VERSION/" && \ "$JAR" xvf "$SOURCE_PATH/wfdb-swig.jar" wfdb.jar && \ "$JAR" xvf "$SOURCE_PATH/wfdb-swig-matlab-$OS.jar" wsm-classes.jar && \ "$JAR" xvf "$SOURCE_PATH/wsm-matlab-code.jar" && \ cd "lib-$ARCH" && \ "$JAR" xvf "$SOURCE_PATH/wfdb-nativelibs-$OS-$ARCH.jar" && \ popd >/dev/null) # remove the extraneous stuff that got unjarred rm "$WSM_TEMP_DIR/$WSM_VERSION/matlab-files.txt" rm -r "$WSM_TEMP_DIR/$WSM_VERSION/META-INF" for f in "$WSM_TEMP_DIR/$WSM_VERSION/lib-$ARCH/"* do if [[ "$f" != *"-$ARCH" ]] then rm -r "$f" fi done # rename the shared libs. for lf in "$WSM_TEMP_DIR/$WSM_VERSION/lib-$ARCH/"*"-$ARCH" do mv "$lf" "$WSM_TEMP_DIR/$WSM_VERSION/lib-$ARCH/$(basename $lf -$ARCH)" done # check that these jars exist if [ ! -e "$WSM_TEMP_DIR/$WSM_VERSION/wfdb.jar" ] then echo "*** Error: $SOURCE_PATH/wfdb-swig.jar does not appear to contain wfdb.jar" 1>&2 exit 1 fi if [ ! -e "$WSM_TEMP_DIR/$WSM_VERSION/wsm-classes.jar" ] then echo "*** Error: $SOURCE_PATH/wfdb-swig-matlab-$OS.jar does not appear to contain wsm-classes.jar" 1>&2 exit 1 fi # FIXME: should probably check that the other files are there, too # # if we downloaded from the web site, remove the temp. dir. # if [ ! -z "$TEMP_JAR_DIR" ] then rm -r "$TEMP_JAR_DIR" fi # # update classpath.txt and librarypath.txt, into temp. files # FIXME: why doesn't [[:graph:]]+ work??? # SED_PROG='1{h;$p;d;};x;G;/^# DO NOT EDIT: WSM v\. [[:graph:]][[:graph:]]* [[:graph:]][[:graph:]]* \(.*\)\n\1$/!{P;$!d;g;p;};$!{n;h;${g;p;};d;}' sed -n -e "$SED_PROG" "$MATLAB/toolbox/local/classpath.txt" \ > "$WSM_TEMP_DIR/classpath.txt" sed -n -e "$SED_PROG" "$MATLAB/toolbox/local/librarypath.txt" \ > "$WSM_TEMP_DIR/librarypath.txt" WSM_CODE_DIR="$WSM_FINAL_DIR/$WSM_VERSION" WSM_LIB_DIR="$WSM_CODE_DIR/lib-$ARCH" NEW_UUID=$(make_uuid) WSM_COMMENT_PREFIX="# DO NOT EDIT: WSM v. $WSM_VERSION $NEW_UUID" echo "$WSM_COMMENT_PREFIX $WSM_LIB_DIR" >> "$WSM_TEMP_DIR/librarypath.txt" echo "$WSM_LIB_DIR" >> "$WSM_TEMP_DIR/librarypath.txt" echo "$WSM_COMMENT_PREFIX $WSM_CODE_DIR/wfdb.jar" >> "$WSM_TEMP_DIR/classpath.txt" echo "$WSM_CODE_DIR/wfdb.jar" >> "$WSM_TEMP_DIR/classpath.txt" echo "$WSM_COMMENT_PREFIX $WSM_CODE_DIR/wsm-classes.jar" \ >> "$WSM_TEMP_DIR/classpath.txt" echo "$WSM_CODE_DIR/wsm-classes.jar" >> "$WSM_TEMP_DIR/classpath.txt" # # write config file # WSM_CONF_FILE="$WSM_TEMP_DIR/$WSM_VERSION.conf" touch "$WSM_CONF_FILE" echo "$NEW_UUID" >> "$WSM_CONF_FILE" echo "$MATLAB_VERSION" >> "$WSM_CONF_FILE" echo "$MATLAB" >> "$WSM_CONF_FILE" # # create backups of classpath.txt and librarypath.txt # echo echo "Just so you know, I'm going to put backups of classpath.txt and" echo "librarypath.txt into $WSM_FINAL_DIR, before I change them." cp "$MATLAB/toolbox/local/classpath.txt" "$WSM_TEMP_DIR/classpath.txt.backup" cp "$MATLAB/toolbox/local/librarypath.txt" "$WSM_TEMP_DIR/librarypath.txt.backup" # # move temp. dir. to final dir. # if [ -e "$WSM_FINAL_DIR" ] then echo read_char_prompt "$WSM_FINAL_DIR already exists; can I replace it? \ (If not, installation will abort.)" \ "yn" if [ "$RESULT" = "n" ] then echo "OK, I'm aborting. If you want, you can finish manually:" echo "copy $WSM_TEMP_DIR/classpath.txt into $MATLAB/toolbox/local/ and" echo "copy $WSM_TEMP_DIR/librarypath.txt into $MATLAB/toolbox/local/ and then" echo "move $WSM_TEMP_DIR to $WSM_FINAL_DIR." echo "Everything should work after that!" exit 1 fi rm -rf "$WSM_FINAL_DIR" fi echo echo "OK, moving $WSM_TEMP_DIR to $WSM_FINAL_DIR ..." if [ ! -e "$(dirname "$WSM_FINAL_DIR")" ] then mkdir -p "$(dirname "$WSM_FINAL_DIR")" fi mv "$WSM_TEMP_DIR" "$WSM_FINAL_DIR" # # move temp. classpath.txt and librarypath.txt into $MATLAB/toolbox/local # FIXME: why can't i figure out how to run run_su on multiple commands?? # echo echo "OK, now I have to copy classpath.txt and librarypath.txt" echo " into $MATLAB/toolbox/local/." if [ -z "$INSTALL_GLOBALLY" ] then echo " You may be prompted for a password (maybe more than once.)" fi for pf in classpath.txt librarypath.txt do { cp "$WSM_FINAL_DIR/$pf" \ "$MATLAB/toolbox/local/$pf" 2>/dev/null; } || \ { [ -z "$INSTALL_GLOBALLY" ] && \ { run_su cp "$WSM_FINAL_DIR/$pf" \ "$MATLAB/toolbox/local/$pf"; }; } rm -f "$WSM_FINAL_DIR/$pf" done # # FIXME: need to escape the paths! # FIXMEFIXME: use the userpath! # echo echo "OK, updating MATLAB path ..." if [ -z "$INSTALL_GLOBALLY" ] then "$MATLABBIN" -nodesktop -nodisplay -nosplash \ -r "addpath('$WSM_FINAL_DIR/$WSM_VERSION'); \ addpath('$WSM_FINAL_DIR/$WSM_VERSION/util'); \ mkdir('$HOME','matlab'); \ path2rc('$HOME/matlab/pathdef.m'); \ exit;" >/dev/null else "$MATLABBIN" -nodesktop -nodisplay -nosplash \ -r "addpath('$WSM_FINAL_DIR/$WSM_VERSION'); \ addpath('$WSM_FINAL_DIR/$WSM_VERSION/util'); \ path2rc; \ exit;" >/dev/null fi # # # echo echo "All done! Enjoy!" echo