#! /bin/bash
#
# wr_install - script to install XicTools packages.
# For XicTools-4.3 (open source) branch ONLY.
#
# Whiteley Research Inc., open source, Apache 2.0 license
# Stephen R. Whiteley 9/23/2017

# Usage: wr_install [-t] distrib_file ...
#
# The arguments are XicTools package files as obtained (for example)
# from the Whiteley Research web site.  DO NOT CHANGE THE NAMES OF
# THESE FILES!  If "-t" is given, files that follow won't be
# installed, but the commands that would be executed are printed.

# This script is also called by Xic and WRspice when doing updates
# through the programs, using "wr_install -upd distrib_file prefix".

# Unlike earlier releases, this script does NOT implement Safe
# Install, which is now implemented in the pre/post install scripts
# built into the distribution files and called during installation. 
# This script is now just a simple wrapper around the native
# installation tools.

# In XicTools-4.3, Safe Install applies to all supported operating
# systems, including Microsoft Windows.  This applies to Xic and
# WRspice only.  In Safe Install, during an update the previous
# release is saved in its entirety, and can be reveerted to if there
# is a problem with the new release.  The user can remove the old
# release by manually deleting its directory tree at any time.

# Safe Install is implemented within the distribution installation
# logic itself, and does not require external scripts (like this one)
# for support.

# The installation scripts in the distribution files now link all
# executable programs from the Xic and WRspice distributions into
# /usr/local/xictools/bin.  Only this directory is needed in your
# shell search path.  The directories /usr/local/xictools/xic/bin and
# /usr/local/xictools/wrspice/bin, which were previously needed in the
# path should be removed if present.

# Here's the safe install logic, for example for xic.  The present
# release is installed under xic.current, and the previous release
# saved under xic-version (where version is the release number, e.g.
# 4.2.15), both under /usr/local/xictools (by default).  The
# xic.current directory is symbolically linked as "xic" in the same
# directory.

# When updating, the distribution pre-install script will remove the
# link to xic, then move xic.current to xic-version.  The basic update
# is then done, which will install a new xic.current.  Finally the
# symbolic link from xic.current as xic is created.  Further, links
# are created to each of the executable programs under the xic link in
# the /usr/local/xictools/bin directory, so that all programs can be
# found in this directory, which should be in the user's shell search
# path.

# If there is a problem with the new release, the maintainer can
# delete the link from xic.current to xic, and recreate the link, but
# point it to xic-version.  Then you're back to running the previous
# release, completely as it was.

# Note that the previous installed releases will all be saved as
# xic-version, and can be reverted to if needed.  The user can delete
# these old releases when they are no longer of potential value.  The
# release in xic.current is registered with the system package
# database and should only be uninstalled using your package manager
# program, or the wr_uninstall script available from Whiteley
# Research.  In Windows, one can use the Windows Add/Remove software
# window to remove packages, or use the wr_uninstall.bat script from a
# command window, or use the wr_uninstall script from a Cygwin window.

#=======================================================================

command -v sudo 2>&1 > /dev/null
if [ $? != 0 ]; then
    echo
    echo \
"ERROR:
The sudo command is not found.  You can fake it by creating a file
named \"sudo\" somewhere in your search path, with content

#!/bin/bash
\$@

Make the file executable with "chmod 755 sudo".  This creates a
phony sudo command that simply executes the arguments.  You may need
to run the calling script as an administrator or root user."
    exit 1
fi

script_path=$(dirname $0)
PATH=$PATH:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin

usage()
{
    echo
    echo "Usage:  wr_install [-t] arg ..."
    echo
    echo \
"The arguments can be partial program names from among those listed below:"
    echo "  $*."
    echo \
"Only the first few characters, to uniquely specify the name, are
required in each argument.  For each argument, if a corresponding
XicTools-4.3 package file is found in this directory, it will be
installed.  The arguments can also be the actual full names of
XicTools-4.3 package files found in the this directory."

    echo
    echo "DO NOT CHANGE THE NAMES OF THE PACKAGE FILES!"
    echo
    echo \
"If \"-t\" is given, packages that follow won't be installed, but the
commands that would otherwise be executed are printed."
    echo
    echo \
"See the comments at the top of the script file for more information.
This version is not compatible with pre-4.3 releases."
    echo
    echo \
"It is likely that you will need administrator or super-user
permissions to successfully install packages.  Except under Windows,
the sudo utility is used to grant root permission.  You must be listed
in /etc/sudoers, and give YOUR (not root's) password when asked."
    echo
}

# Return the (filled in as needed) full path for $1.
#
fullpath()
{
    echo $(cd $(dirname "$1") && pwd -P)/$(basename "$1")
}

# Remove a pre-4.3 XicTools installation from Linux/rpm.  The user is
# given the option of saving existing Xic and WRspice installations
# into the Safe Install framework.  Existing Safe Installs are
# preserved.
#
remove_rpm_dist()
{
    prog=$1
    dist=$2

    if [ $prog = xic -o $prog = wrspice ]; then
        loc=$(rpm -ql $dist | grep xictools/$prog/bin/$prog\$)
        loc=${loc%/$prog/bin/$prog}
        if [ -n "$loc" ]; then
            echo
            echo Reverting Safe Install linking
            echo "cd $loc; rm $prog; mv -f $prog.current $prog"
            if [ $dryrun = no ]; then
                sudo bash -c "cd $loc; rm $prog; mv -f $prog.current $prog"
            fi
            echo
            echo -n ">>>  Save $loc/$prog ? [n] "
            read foo
            if [ x$foo = xy -o x$foo = xyes ]; then
                vstr=$($loc/$prog/bin/$prog --v)
                set -- $vstr
                vstr=$1
                echo
                echo Saving $prog-$vstr
                echo "cd $loc; cp -prf $prog $prog-$vstr"
                if [ $dryrun = no ]; then
                    sudo bash -c "cd $loc; cp -prf $prog $prog-$vstr"
                fi
            fi
            echo
            echo "***IMPORTANT!  Remove $loc/$prog/bin from your search path. ***"
            echo
        fi
    fi

    echo
    echo Removing package $a
    echo rpm -e $a
    if [ $dryrun = no ]; then
        sudo rpm -e $a
    fi
}

# Remove a pre-4.3 XicTools installation under OS X.  The user is
# given the option of saving existing Xic and WRspice installations
# into the Safe Install framework.  Existing Safe Installs are
# preserved.
#
remove_osx_dist()
{
    prog=$1
    dist=$2

    # Apple packages aren't relocatable.
    loc=/usr/local/xictools

    if [ $prog = xic -o $prog = wrspice ]; then
        if [ -x $loc/$prog/bin/$prog ]; then
            echo
            echo Reverting Safe Install linking
            echo "cd $loc; rm $prog; mv -f $prog.current $prog"
            if [ $dryrun = no ]; then
                sudo bash -c "cd $loc; rm $prog; mv -f $prog.current $prog"
            fi
            echo
            echo -n ">>>  Save $loc/$prog ? [n] "
            read foo
            if [ x$foo = xy -o x$foo = xyes ]; then
                vstr=$($loc/$prog/bin/$prog --v)
                set -- $vstr
                vstr=$1
                echo
                echo Saving $prog-$vstr
                echo "cd $loc; cp -prf $prog $prog-$vstr"
                if [ $dryrun = no ]; then
                    sudo bash -c "cd $loc; cp -prf $prog $prog-$vstr"
                fi
            fi
            echo
            echo "***IMPORTANT!  Remove $loc/$prog/bin from your search path. ***"
            echo
        fi
    fi

    echo
    echo Removing package $a
    case $prog in
    xic)
        if [ $dryrun = yes ]; then
            echo rm -rf $loc/$prog
            echo rm -f $loc/bin/xic
            echo rm -f $loc/bin/wrdecode
            echo rm -f $loc/bin/wrencode
            echo rm -f $loc/bin/wrsetpass
            echo pkgutil --forget $dist
        else
            sudo rm -rf $loc/$prog
            sudo rm -f $loc/bin/xic
            sudo rm -f $loc/bin/wrdecode
            sudo rm -f $loc/bin/wrencode
            sudo rm -f $loc/bin/wrsetpass
            sudo pkgutil --forget $dist
        fi
        ;;
    wrspice)
        if [ $dryrun = yes ]; then
            echo rm -rf $loc/$prog
            echo rm -f $loc/bin/multidec
            echo rm -f $loc/bin/proc2mod
            echo rm -f $loc/bin/printtoraw
            echo rm -f $loc/bin/wrspice
            echo rm -f $loc/bin/wrspiced
            echo pkgutil --forget $dist
        else
            sudo rm -rf $loc/$prog
            sudo rm -f $loc/bin/multidec
            sudo rm -f $loc/bin/proc2mod
            sudo rm -f $loc/bin/printtoraw
            sudo rm -f $loc/bin/wrspice
            sudo rm -f $loc/bin/wrspiced
            sudo pkgutil --forget $dist
        fi
        ;;
    xt_accs)
        if [ $dryrun = yes ]; then
            echo rm -rf $loc/mozy
            echo rm -f $loc/bin/mozy
            echo rm -f $loc/bin/xeditor
            echo rm -f $loc/bin/httpget
            echo rm -f $loc/bin/hlp2html
            echo rm -f $loc/bin/hlpsrv
            echo rm -f $loc/bin/fcpp
            echo rm -f $loc/bin/lstpack
            echo rm -f $loc/bin/lstunpack
            echo pkgutil --forget $dist
        else
            sudo rm -rf $loc/mozy
            sudo rm -f $loc/bin/mozy
            sudo rm -f $loc/bin/xeditor
            sudo rm -f $loc/bin/httpget
            sudo rm -f $loc/bin/hlp2html
            sudo rm -f $loc/bin/hlpsrv
            sudo rm -f $loc/bin/fcpp
            sudo rm -f $loc/bin/lstpack
            sudo rm -f $loc/bin/lstunpack
            sudo pkgutil --forget $dist
        fi
        ;;
    xtlserv)
        if [ $dryrun = yes ]; then
            echo rm -f $loc/license/README
            echo rm -f $loc/bin/xtlserv
            echo rm -f $loc/bin/xtjobs
            echo pkgutil --forget $dist
        else
            sudo rm -f $loc/license/README
            sudo rm -f $loc/bin/xtlserv
            sudo rm -f $loc/bin/xtjobs
            sudo pkgutil --forget $dist
        fi
        ;;
    esac
}

# Identify obsolete installed packages, and remove them.
#
clean_old()
{
    if [ $dryrun = yes ]; then
        echo Cleaning old packages in dry run mode.
    else
        echo Cleaning old packages.
    fi

    if [ $(uname) = Darwin ]; then
        xiclist=$(pkgutil --pkgs | grep "^XicTools\.Xic\.")
        wrslist=$(pkgutil --pkgs | grep "^XicTools\.WRspice\.")
        acslist=$(pkgutil --pkgs | grep "^XicTools\.Accs\.")
        srvlist=$(pkgutil --pkgs | grep "^XicTools\.Xtlserv\.")

        for a in $xiclist; do
            remove_osx_dist xic $a
        done

        for a in $wrslist; do
            remove_osx_dist wrspice $a
        done

        for a in $acslist; do
            remove_osx_dist xt_accs $a
        done

        for a in $srvlist; do
            remove_osx_dist xtlserv $a
        done
        # Record that we've been run.
        if [ $dryrun = no ]; then
            echo "4.3" > $HOME/.wrclean
        fi
        echo Cleaning done.
        return
    fi

    command -v rpm 2>&1 > /dev/null
    if [ $? = 0 ]; then
        xiclist=$(rpm -qa | grep "^xic-")
        wrslist=$(rpm -qa | grep "^wrspice-")
        acslist=$(rpm -qa | grep "^xt_accs-")
        srvlist=$(rpm -qa | grep "^xtlserv-")

        for a in $xiclist; do
            remove_rpm_dist xic $a
        done

        for a in $wrslist; do
            remove_rpm_dist wrspice $a
        done

        for a in $acslist; do
            remove_rpm_dist xt_accs $a
        done

        for a in $srvlist; do
            remove_rpm_dist xtlserv $a
        done
        # Record that we've been run.
        if [ $dryrun = no ]; then
            echo "4.3" > $HOME/.wrclean
        fi
        echo Cleaning done.
        return
    fi

    command -v dpkg 2>&1 > /dev/null
    if [ $? = 0 ]; then
        # Nothing to clean, support is new.
        # Record that we've been run.
        if [ $dryrun = no ]; then
            echo "4.3" > $HOME/.wrclean
        fi
        echo Cleaning done.
        return
    fi

    echo Packaging system unsupported.
    exit 1
}

check_clean()
{
    if [ -f $HOME/.wrclean ]; then
        read resp < $HOME/.wrclean
    fi
    if [ x$resp != x4.3 ]; then
        echo
        echo \
"The following operation will remove all pre-4.3 packages.  Your
present Xic and WRspice can be saved using the \"Safe Install\"
format, and existing safe-installs won't be touched.  This utility
will be run once only, before 4.3 packages are installed."
        if [ $dryrun = yes ]; then
            echo
            echo \
"You gave \"-t\" so the operation won't actually do anything, only
print commands it would otherwise execute."
        fi
        echo
        echo -n "Run now? [n]: "
        read resp
        if [ x$resp = xy -o x$resp = xyes ]; then
            if [ $windows = yes ]; then
                if [ $dryrun = yes ]; then
                    $script_path/cleanold.bat /t
                else
                    $script_path/cleanold.bat
                    # Record that we've been run.
                    if [ $dryrun = no ]; then
                        echo "4.3" > $HOME/.wrclean
                    fi
                    echo Cleaning done.
                fi
            else
                clean_old
            fi
        else
            if [ $dryrun = no ]; then
                echo Aborting.
                exit 0
            fi
        fi
    fi
}

# Do the installation, removing old installation(s) first when possible.
# arguments: distfile prefix
#
do_update()
{
    distfile=$1
    prefix=$2

    if [ -z "$distfile" ]; then
        echo "Error: (do_update) no file name given!"
        return 127
    fi
    if [ ! -f $distfile ]; then
        echo File: $distfile
        echo "Error: (do_update) file $distfile not found."
        return 127
    fi
    if [ -z "$prefix" ]; then
        echo "Error: (do_update) no prefix given!"
        return 127
    fi

    dfb=`basename $distfile`
    tmpifs="$IFS"
    IFS="-"
    set -- $dfb
    progname=$1
    osname=$2
    vers=$3
    arch=$4
    IFS="."
    set -- $vers
    release_lev=$1
    release_maj=$2
    set -- $arch
    arch=$1
    sfx=$2
    fullprogname=$progname
    IFS="_"
    set -- $progname
    xt=$1
    progname=$2
    IFS=$tmpifs

    if [ -z "$osname" ]; then
        echo "Error: (do_update) OSNAME not found in distfile name!"
        return 127
    fi
    if [ -z "$vers" ]; then
        echo "Error: (do_update) VERSION not found in distfile name!"
        return 127
    fi

    # All 4.3 distribution files have a program name field in the form
    # xictools_progname.  This was split at the underscore, xt is the
    # first token, progname the second.

    if [ x$xt != xxictools ]; then
        nmok=no
        case $osname in
        Darwin*|Win*)
        if [ x$xt = xgtk2 -a x$progname = xbundle ]; then
            nmok=yes
        fi
        ;;
        esac

        if [ $nmok = no ]; then
            echo File: $distfile
            echo \
      "Warning: file is not an XicToole-4.3 distribution, install anyway? [n] "
            read resp
            if [ x"$resp" != xy -a x"$resp" != xyes ]; then
                return 0
            fi
        fi
        progname=$fullprogname
    fi

    case $osname in
    Darwin*)
        if [ $prefix != /usr/local ]; then \
            echo "Xictools packages for OS X are not relocatable."
            return 127
        fi
        ppkg=`fullpath $distfile`
        echo sudo installer -pkg "$ppkg" -target /
        if [ $dryrun = no ]; then
            sudo installer -pkg "$ppkg" -target /
        fi
        ;;

    Win32)
	if [ ! -x $distfile ]; then
            echo File: $distfile
            echo Error: file not executable.
            return 127
        fi
        echo ./$distfile
        if [ $dryrun = no ]; then
            ./$distfile
        fi
        ;;

    Linux*)
        if [ x$sfx = xrpm ]; then
            command -v rpm >/dev/null 2>&1
            if [ $? != 0 ]; then
                echo "Error: can't find rpm command."
                return 127
            fi
            if [ $prefix = /usr/local ]; then
                echo rpm -U --replacepkgs --replacefiles --nodeps $distfile
                if [ $dryrun = no ]; then
                    sudo rpm -U --replacepkgs --replacefiles --nodeps $distfile
                fi
            else
                echo rpm -U --replacepkgs --replacefiles --nodeps --relocate /usr/local=$prefix $distfile
                if [ $dryrun = no ]; then
                    sudo rpm -U --replacepkgs --replacefiles --nodeps --relocate /usr/local=$prefix $distfile
                fi
            fi
        elif [ x$sfx = xdeb ]; then
            command -v dpkg >/dev/null 2>&1
            if [ $? != 0 ]; then
                echo "Error: can't find dpkg command."
                return 127
            fi
            if [ $prefix != /usr/local ]; then
                echo Debian packages are not relocatable, can install under
                echo /usr/local only.
                return 127
            fi
            echo dpkg -i $distfile
            if [ $dryrun = no ]; then
                sudo dpkg -i $distfile
            fi
        else
            echo Unhandled file extension $sfx, unsupported packager.
            return 127
        fi
        ;;
    *)
        echo "do_update: unknown token $osname"
        return 1
        ;;
    esac

    ret=0
    if [ $dryrun = no ]; then
        ret=$?
        if [ $ret = 0 ]; then
            echo Installation of $progname-$osname-$vers done, no errors returned.
        else
            echo Installation of $progname-$osname-$vers FAILED.
        fi
    fi
    return $ret
}


if [ x$1 = x-upd ]; then
    # Called from package manager when updating
    # wr_install -upd distfile prefix

    distfile=$2
    prefix=$3

    if [ x$prefix = x ]; then
        echo "Too few arguments given."
        echo
        echo "Press Enter to continue."
        read aa
        exit 127
    fi

    do_update $distfile $prefix no
    ret=$?

    echo
    echo "Press Enter to continue."
    read aa
    exit $ret
fi


programs="adms fastcap fasthenry mozy mrouter vl wrspice xic xtlserv"
if [ $# = 0 ]; then
    usage $programs
    exit 1
fi

myname=$0

dryrun=no
list=$*
for a in $list; do
    case $a in
    al|all)
        if [ $dryrun = yes ]; then
            list="-t $programs"
        else
            list=$programs
        fi
        break
        ;;
    -t)
        dryrun=yes
        ;;
    esac
done

shopt -s nullglob

pkgs=""
for a in $list; do
    case $a in
    -t)
        pkgs="$pkgs $a"
    ;;
    ad|adm|adms)
	pkg=xictools_adms-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    fc|fastc|fastca|fastcap)
	pkg=xictools_fastcap-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    fh|fasth|fasthe|fasthen|fasthenr|fasthenry)
	pkg=xictools_fasthenry-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    mo|moz|mozy)
	pkg=xictools_mozy-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    mr|mro|mrou|mrout|mroute|mrouter)
	pkg=xictools_mrouter-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    v|vl)
	pkg=xictools_vl-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    w|wr|wrs|wrsp|wrspi|wrspic|wrspice)
	pkg=xictools_wrspice-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    xi|xic)
	pkg=xictools_xic-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    xt|xtl|xtls|xtlse|xtlser|xtlserv)
	pkg=xictools_xtlserv-*
	if [ -n "$pkg" ]; then
            pkgs="$pkgs $pkg"
        fi;;
    *)
        if [ -f $s ]; then
            pkgs="$pkgs $a"
        fi
    esac
done

if [ -z "$pkgs" ]; then
    echo "Nothing found to install."
    usage $programs
    exit 1
fi

windows=no
if [ -n "$COMSPEC" ]; then
    if [ -n "$(expr match $COMSPEC '.*\(\.exe\)')" ]; then
        windows=yes
    fi
fi

cleanchk=no
dryrun=no
if [ $windows = yes ]; then
    ret=0
    for fname in $pkgs; do
        if [ $fname = "-t" ]; then
            dryrun=yes
            continue
        fi
        if [ $cleanchk = no ]; then
            check_clean
            cleanchk=yes
        fi
        do_update $fname /usr/local
        r=$?
        if [ r != 0 ]; then
            ret=1
        fi
    done
    exit $ret
fi

if [ $(whoami) != root ]; then
    if [ x$1 != x -a x$1 != x-t ]; then
        echo "You're not root, validating using sudo."
        sudo -v
        if [ $? != 0 ]; then
            echo Validation failed.
            exit 1
        fi
    fi
fi

prefix=
ret=0
for fname in $pkgs; do
    if [ $fname = "-t" ]; then
        dryrun=yes
        continue
    fi
    if [ $cleanchk = no ]; then
        check_clean
        cleanchk=yes
    fi
    if [ -z "$prefix" ]; then
        sfx=${fname##*.}
        if [ x$sfx = xpkg ]; then
            # Apple packages aren't relocatable
            prefix=/usr/local
        elif [ x$sfx = xdeb ]; then
            # Debian/Ubuntu packages aren't relocatable
            prefix=/usr/local
        else
            prefix=$XT_PREFIX
            if [ x"$prefix" = x ]; then
                prefix=/usr/local
            fi
            while [ 1 = 1 ]; do
                printf "Distributions will be installed under\n\
  $prefix\nIs this OK [y/n]? "
                read resp
                if [ x"$resp" = xn -o x"$resp" = xno ]; then 
                    printf "Enter prefix to use instead of\n  $prefix\n> "
                    read prefix
                    continue
                elif [ x"$resp" = xy -o x"$resp" = xyes ]; then
                    break
                else
                    echo Next time answer y or n.
                fi
            done
        fi
    fi

    do_update $fname $prefix
    r=$?
    if [ r != 0 ]; then
        ret=1
    fi
done
exit $ret