Skip to content

Instantly share code, notes, and snippets.

@johnjcamilleri
Created November 10, 2015 13:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnjcamilleri/1ed5db5eb4bd26a97afb to your computer and use it in GitHub Desktop.
Save johnjcamilleri/1ed5db5eb4bd26a97afb to your computer and use it in GitHub Desktop.
activate-hs
#!/bin/sh
quiet=no
verbose=no
dryrun=no
list=no
version="" # forgiving user input version
hpVersion="" # like "2014.2.0.0"
ghcVersion="" # like "7.8.3"
arch="" # "i386" or "x86_64"
hpDirname="" # "2014.2.0.0-x86_64" or older form "ghc-7.6.3"
ghcDirname="" # "7.8.3-x86_64"
hpInstallDir="/Library/Haskell"
ghcInstallDir="/Library/Frameworks/GHC.framework/Versions"
msg=""
findItems() {
( cd "$1" && ls -d -1 ${2:-*} ) 2>/dev/null
}
###
### Version and Arch Mechanics
###
extractVersions() {
# takes a very liberal set of formats, and figures out the version info:
# ver ghc version
# ver-arch ghc version and arch, also dirname in GHC installs
# and newer HP installs
# ghc-ver dirnames used in older HP installs
# in each case, ver can be x.y or x.y.z
hpVersion=""
ghcVersion=""
arch=""
msg=""
input="${1#ghc-}" # remove ghc- prefix if present
case "$input" in
*-*) arch="${input#*-}"
input="${input%-*}"
;;
esac
case "$input" in
7.6.3) ghcVersion="$input" ; hpVersion="2013.2.0.0" ;;
7.4.2) ghcVersion="$input" ; hpVersion="2012.4.0.0" ;;
7.4.1) ghcVersion="$input" ; hpVersion="2012.2.0.0" ;;
7.0.4) ghcVersion="$input" ; hpVersion="2011.4.0.0" ;;
7.0.3) ghcVersion="$input" ; hpVersion="2011.2.0.0" ;;
[67].*) ghcVersion="$input" ;;
*) msg="Can't parse $input as a GHC version"
return 1
;;
esac
# see if there is an installed version w/bigger number
for d in $( findItems "$ghcInstallDir" "$ghcVersion"'*' ) ; do
ghcVersion="${d%-*}" # last one will be highest!
ghcArch="${d#*-}"
done
if [ -z "$arch" ] ; then
arch="${ghcArch}"
fi
if [ -z "$arch" ] ; then
msg="Can't determine architecture, please specify one (i386 or x86_64)"
return 1
fi
ghcDirname="$ghcVersion-$arch"
ghcRoot="$ghcInstallDir/$ghcDirname"
if [ \! -d "$ghcRoot" ] ; then
msg="GHC $ghcVersion $arch not found in $ghcInstallDir"
return 1
fi
# see if there is an installed platform to match
if [ -d "$hpInstallDir/ghc-$ghcVersion" ] ; then
# old style platform install
hpDirname="ghc-$ghcVersion"
hpRoot="$hpInstallDir/$hpDirname"
for r in $( findItems "$hpRoot/lib/registrations" 'haskell-platform-*.conf' ) ; do
q="${r#haskell-platform-}"
hpVersion="${q%.conf}"
done
elif [ -d "$hpInstallDir/ghc-$ghcVersion-$arch" ] ; then
# new style platform install
hpDirname="ghc-$ghcVersion-$arch"
hpRoot="$hpInstallDir/$hpDirname"
for v in $( findItems "$hpRoot" 'version-*' ) ; do
hpVersion="${v#version-}"
done
else
hpVersion="--none--"
hpDirname=""
hpRoot=""
fi
return 0
}
###
### Decode arguments
###
usage() {
echo "$0 -l"
echo "$0 [-q | -v] [-n] [ version [ arch ] ]"
echo " -l | --list just list installed versions"
echo " -q | --quiet supress informational output"
echo " -v | --verbose print actions as they are taken"
echo " -n | --dryrun don't actually do anything (implies -v)"
echo ""
echo " version ex. 7.8.3, defaults to latest"
echo " arch i386 or x86_64, defaults to what's installed"
}
originalArgs="$*"
while [ $# -gt 0 ]
do
case "$1" in
-l|--list) list=yes ;;
-q|--quiet) quiet=yes ; verbose=no ;;
-v|--verbose) quiet=no ; verbose=yes ;;
-n|--dryrun) dryrun=yes ;;
-f|--force) force=yes ;;
-\?|--help) usage ; exit 0 ;;
-*) echo "Unknown flag $1" ; usage ; exit 1 ;;
*) if [ -z "$version" ] ; then
version="$1"
elif [ -z "$arch" ] ; then
arch="$1"
else
echo "Too many non-option arguments" ; usage ; exit 1
fi
;;
esac
shift
done
if [ "$list" = "yes" ] ; then
for version in $( findItems "$ghcInstallDir" ) ; do
if extractVersions $version ; then
if [ -n "$hpRoot" ] ; then
echo "$ghcVersion-$arch - with platform $hpVersion"
if [ "$verbose" = "yes" ] ; then
echo " ghc at $ghcRoot"
echo " platform at $hpRoot"
fi
else
echo "$ghcVersion $arch - no platform"
if [ "$verbose" = "yes" ] ; then
echo " ghc at $ghcRoot"
fi
fi
fi
done
exit 0
fi
###
### Validate haskell platform version
###
if [ -z "$version" ] ; then
version=$( ( for d in $( findItems "$ghcInstallDir" ) ; \
do extractVersions "$d" && echo "$ghcVersion" ; \
done ) \
| sort -t '.' -n | tail -1 )
fi
if extractVersions $version ; then
ok="yes"
else
if [ -z "$version" ] ; then
echo "No GHC or Platform versions installed in /Library"
else
echo "$msg"
fi
exit 1
fi
if [ \! -d "$hpRoot" -a "$quiet" = "no" ] ; then
echo "Warning: No corresponding Haskell Platform found"
fi
###
### Check for Xcode command line tools
###
if [ \! \( -f /usr/bin/gcc -a -x /usr/bin/gcc \) ] ; then
echo "There is no compiler installed at /usr/bin/gcc"
echo "Install Xcode's command line tools, or another compiler tool chain."
exit 1
fi
###
### Root check
###
if [ "$dryrun" = "no" -a `id -u` -ne 0 ]
then
echo "You must be root to activate a particular Haskell Platform."
echo "Please rerun this command sudo:"
echo " sudo $0 $originalArgs"
exit 1
fi
###
### Get ready to actually do stuff
###
if [ "$dryrun" = "yes" -a "$verbose" = "yes" ] ; then
echo "Dry run mode enabled, would have run the following commands:"
fi
run() {
if [ "$verbose" = "yes" ] ; then
echo " $*"
fi
if [ "$dryrun" = "no" ] ; then
"$@"
fi
}
symLink() {
run rm -rf "$2"
run ln -sf "$1" "$2"
}
symLinkInto() {
run ln -sf "$@"
}
###
### Fix up bits in platform tree
###
if [ -d "$hpRoot" ] ; then
if [ -x $hpRoot/bin/cabal.wrap ]
then
run mv $hpRoot/bin/cabal $hpRoot/bin/cabal.real
symLink cabal.wrap $hpRoot/bin/cabal
fi
symLink $ghcRoot/usr/share/doc/ghc/html $hpRoot/doc/ghc-doc
symLink $ghcRoot/usr/share/doc/ghc/html/libraries/ghc-$ghcVersion $hpRoot/doc/ghc-api
fi
###
### Repoint current links
###
symLink $ghcDirname /Library/Frameworks/GHC.framework/Versions/Current
if [ -d "$hpRoot" ] ; then
symLink $hpDirname /Library/Haskell/current
symLink current/bin /Library/Haskell/bin
symLink current/doc /Library/Haskell/doc
fi
###
### Set up /usr
###
symLinkInto $ghcRoot/usr/bin/* /usr/local/bin
symLinkInto $ghcRoot/usr/share/man/man1/* /usr/local/share/man/man1
symLinkInto $ghcRoot/usr/share/doc/ghc /usr/local/share/doc
if [ -d "$hpRoot" ] ; then
symLinkInto $hpRoot/bin/* /usr/local/bin
fi
###
### Patch settings file
extractSetting() {
sed -n -e "/$1/"'s/.*, *"\(.*\)").*/\1/p' $settingsFile
}
updateSetting() {
run sed -e "/$1/"'s/, *".*"/, "'"$2"'"/' -i '.bak' $settingsFile
}
determineCompiler() {
case "$( "$1" --version 2>/dev/null )" in
*clang*) echo clang ;;
*gcc*) echo gcc ;;
*cpphs*) echo cpphs ;;
*) echo unknown ;;
esac
}
settingsFile="$ghcRoot/usr/lib/ghc-$ghcVersion/settings"
if [ -f "$settingsFile" ] ; then
if grep -q '"Haskell CPP flags"' "$settingsFile" ; then
cmd=$( extractSetting "Haskell CPP command" )
case "$( determineCompiler $cmd )" in
clang) cppArgs="-E -undef -traditional -Wno-invalid-pp-token -Wno-unicode -Wno-trigraphs" ;;
gcc) cppArgs="-E -undef -traditional" ;;
hscpp) cppArgs="--cpp -traditional" ;;
*) if [ "$quiet" = "no" ] ; then
echo "Unrecgonized Haskell CPP command $cmd"
echo "Leaving Haskell CPP flags unchanged in settings"
fi
;;
esac
if [ -n "$cppArgs" ] ; then
updateSetting "Haskell CPP flags" "$cppArgs"
fi
else
cmd=$( extractSetting "C compiler command" )
if [ "$( determineCompiler $cmd )" = "clang" ] ; then
wrapperCmd=/usr/bin/ghc-clang-wrapper
if [ -f "$wrapperCmd" -a -e "$wrapperCmd" ] ; then
updateSetting "C compiler command" "$wrapperCmd"
else
echo "The compiler is clang, but $wrapperCmd isn't installed"
echo "Older GHCs may not work unless this is installed"
echo "Install $wrapperCmd and re-run this script"
fi
fi
fi
else
if [ "$( determineCompiler /usr/bin/gcc )" = "clang" ] ; then
echo "The compiler is clang, but ghc $ghcVersion is old"
echo "and has no settings file to change the compiler."
echo "There is no simple work around."
fi
fi
###
### Register platform packages
###
if [ -d "$hpRoot" ] ; then
for conf in $hpRoot/lib/registrations/*
do
run /usr/bin/ghc-pkg register --verbose=0 --force $conf 2>/dev/null
done
fi
###
### Report
###
if [ "$quiet" = "no" ] ; then
if [ "$dryrun" = "no" ] ; then
verb="now set to"
else
verb="would be set to"
fi
echo
echo "Haskell $verb:"
echo " GHC $ghcVersion"
echo " Arch. $arch"
echo " Platform $hpVersion"
if [ "$dryrun" = "no" ] ; then
echo ""
echo "View documentation with this command:"
echo " open /Library/Haskell/doc/start.html"
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment