|
- #!/bin/sh
- #
- # Copyright (c) 2018, Julian Ospald <hasufell@posteo.de>
- # All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are met:
- #
- # 1. Redistributions of source code must retain the above copyright notice,
- # this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- # 3. Neither the name of the <ORGANIZATION> nor the names of its
- # contributors may be used to endorse or promote products derived from
- # this software without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- # POSSIBILITY OF SUCH DAMAGE.
-
-
-
-
-
- ##########################
- #--[ Global Variables ]--#
- ##########################
-
-
- # @VARIABLE: VERSION
- # @DESCRIPTION:
- # Version of this script.
- VERSION=0.0.8
-
- # @VARIABLE: SCRIPT
- # @DESCRIPTION:
- # Name of this script. This will be the
- # shell name if this script is sourced, so
- # only rely on this for echos and trivial things.
- SCRIPT="$(basename "$0")"
-
- # @VARIABLE: VERBOSE
- # @DESCRIPTION:
- # Whether to print verbose messages in this script.
- VERBOSE=false
-
- # @VARIABLE: FORCE
- # @DESCRIPTION:
- # Whether to force installation and overwrite files.
- FORCE=false
-
- # @VARIABLE: GHCUP_INSTALL_BASE_PREFIX
- # @DESCRIPTION:
- # The main install directory prefix, under which .ghcup
- # directory will be created. This directory is user
- # configurable via the environment variable of the
- # same name. It must be non-empty and the path
- # it points to must exist.
- : "${GHCUP_INSTALL_BASE_PREFIX:=$HOME}"
-
- # @VARIABLE: INSTALL_BASE
- # @DESCRIPTION:
- # The main install directory where all ghcup stuff happens.
- INSTALL_BASE="$GHCUP_INSTALL_BASE_PREFIX/.ghcup"
-
- # @VARIABLE: GHC_LOCATION
- # @DESCRIPTION:
- # The location where ghcup will install different ghc versions.
- # This is expected to be a subdirectory of INSTALL_BASE.
- GHC_LOCATION="$INSTALL_BASE/ghc"
-
- # @VARIABLE: BIN_LOCATION
- # @DESCRIPTION:
- # The location where ghcup will create symlinks for GHC binaries.
- # This is expected to be a subdirectory of INSTALL_BASE.
- BIN_LOCATION="$INSTALL_BASE/bin"
-
- # @VARIABLE: CACHE_LOCATION
- # @DESCRIPTION:
- # The location where ghcup will put tarballs for caching.
- # This is expected to be a subdirectory of INSTALL_BASE.
- CACHE_LOCATION="$INSTALL_BASE/cache"
-
- # @VARIABLE: DOWNLOADER
- # @DESCRIPTION:
- # What program to use for downloading files.
- DOWNLOADER="curl"
-
- # @VARIABLE: DOWNLOADER_OPTS
- # @DESCRIPTION:
- # Options passed to the download program.
- DOWNLOADER_OPTS="-L --fail -O"
-
- # @VARIABLE: DOWNLOADER_STDOUT_OPTS
- # @DESCRIPTION:
- # Options passed to the download program when printing the content to stdout.
- DOWNLOADER_STDOUT_OPTS="-L --fail"
-
- # @VARIABLE: GHC_DOWNLOAD_BASEURL
- # @DESCRIPTION:
- # Base URL for all GHC tarballs.
- GHC_DOWNLOAD_BASEURL="https://downloads.haskell.org/~ghc"
-
- # @VARIABLE: JOBS
- # @DESCRIPTION:
- # How many jobs to use for compiling GHC.
- JOBS="1"
-
- # @VARIABLE: SOURCE
- # @DESCRIPTION:
- # The $0 argument, which contains
- # the script name.
- SOURCE="$0"
-
- # @VARIABLE: BASE_DOWNLOAD_URL
- # DESCRIPTION:
- # The base url for downloading stuff like meta files, requirements files etc.
- BASE_DOWNLOAD_URL="https://gitlab.haskell.org/haskell/ghcup/raw/master/"
-
- # @VARIABLE: SCRIPT_UPDATE_URL
- # @DESCRIPTION:
- # Location to update this script from.
- SCRIPT_UPDATE_URL="${BASE_DOWNLOAD_URL}/ghcup"
-
- # @VARIABLE: META_DOWNLOAD_URL
- # DESCRIPTION:
- # The url of the meta file for getting
- # download information for ghc/cabal-install etc.
- META_DOWNLOAD_URL="${GHCUP_META_DOWNLOAD_URL:=${BASE_DOWNLOAD_URL}/.download-urls}"
-
- # @VARIABLE: META_DOWNLOAD_FORMAT
- # DESCRIPTION:
- # The version of the meta file format.
- # This determines whether this script can read the
- # file from "${META_DOWNLOAD_URL}".
- META_DOWNLOAD_FORMAT="1"
-
- # @VARIABLE: META_VERSION_URL
- # DESCRIPTION:
- # The url of the meta file for getting
- # available versions for ghc/cabal-install etc.
- META_VERSION_URL="${GHCUP_META_VERSION_URL:=${BASE_DOWNLOAD_URL}/.available-versions}"
-
- # @VARIABLE: META_VERSION_FORMAT
- # DESCRIPTION:
- # The version of the meta file format.
- # This determines whether this script can read the
- # file from "${META_VERSION_URL}".
- META_VERSION_FORMAT="1"
-
- # @VARIABLE: BUG_URL
- # DESCRIPTION:
- # The url to report bugs to.
- BUG_URL="https://gitlab.haskell.org/haskell/ghcup/issues"
-
- # @VARIABLE: CACHING
- # @DESCRIPTION:
- # Whether to cache tarballs in $CACHE_LOCATION.
- CACHING=false
-
-
-
- ####################
- #--[ Print Help ]--#
- ####################
-
-
- # @FUNCTION: usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup' to STDERR
- # and exit the script with status code 1.
- usage() {
- (>&2 echo "ghcup ${VERSION}
- GHC up toolchain installer
-
- USAGE:
- ${SCRIPT} [FLAGS] <SUBCOMMAND>
-
- FLAGS:
- -v, --verbose Enable verbose output
- -h, --help Prints help information
- -V, --version Prints version information
- -w, --wget Use wget instead of curl
- -c, --cache Use \"${CACHE_LOCATION}\" for caching tarballs
- (these will not be removed by ghcup)$(${VERBOSE} && printf "\n -o, --os Overwrite OS detection with the given string (must be a correct OS alias, e.g. 'alpine')")
-
- SUBCOMMANDS:
- install Install GHC$(${VERBOSE} && printf "\n compile Compile and install GHC from source (UNSTABLE!!!)")
- set Set currently active GHC version
- list Show available GHCs and other tools
- upgrade Upgrade this script in-place
- rm Remove an already installed GHC
- install-cabal Install cabal-install
- debug-info Print debug info (e.g. detected system/distro)
- changelog Show the changelog of a GHC release (online)
- print-system-reqs Print an approximation of system requirements
-
- DISCUSSION:
- ghcup installs the Glasgow Haskell Compiler from the official
- release channels, enabling you to easily switch between different
- versions.
- ")
- exit 1
- }
-
- # @FUNCTION: install_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup install' to STDERR
- # and exit the script with status code 1.
- install_usage() {
- (>&2 echo "ghcup-install
- Install GHC from binary tarball
-
- USAGE:
- ${SCRIPT} install [FLAGS] [VERSION|TAG]
-
- FLAGS:
- -h, --help Prints help information
- -f, --force Overwrite already existing installation
-
- ARGS:
- [VERSION|TAG] E.g. \"8.4.3\" or \"8.6.1\" or
- a tag like \"recommended\" or \"latest\"
- (default: discovers recommended version)
-
- DISCUSSION:
- Installs the specified GHC version (or a recommended default one) into
- a self-contained \"~/.ghcup/ghc/<ghcver>\" directory
- and symlinks the ghc binaries to \"~/.ghcup/bin/<binary>-<ghcver>\".
- ")
- exit 1
- }
-
- # @FUNCTION: set_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup set' to STDERR
- # and exit the script with status code 1.
- set_usage() {
- (>&2 echo "ghcup-set
- Set the currently active GHC to the specified version
-
- USAGE:
- ${SCRIPT} set [FLAGS] [VERSION|TAG]
-
- FLAGS:
- -h, --help Prints help information
-
- ARGS:
- [VERSION|TAG] E.g. \"8.4.3\" or \"8.6.3\" or
- a tag like \"recommended\" or \"latest\"
- (default: discovers recommended version)
-
- DISCUSSION:
- Sets the the current GHC version by creating non-versioned
- symlinks for all ghc binaries of the specified version in
- \"~/.ghcup/bin/<binary>\".
- ")
- exit 1
- }
-
- # @FUNCTION: upgrade_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup upgrade' to STDERR
- # and exit the script with status code 1.
- upgrade_usage() {
- (>&2 echo "ghcup-upgrade
- Update the ghcup script in-place
-
- USAGE:
- ${SCRIPT} upgrade [FLAGS] [TARGET-LOCATION]
-
- FLAGS:
- -i, --inplace Update this script in-place (wherever it's at)
- -h, --help Prints help information
-
- ARGS:
- [TARGET-LOCATION] Where to place the updated script (defaults to ${BIN_LOCATION}).
- This is ignored if --inplace is issued as well.
- ")
- exit 1
- }
-
- # @FUNCTION: rm_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup rm' to STDERR
- # and exit the script with status code 1.
- rm_usage() {
- (>&2 echo "ghcup-rm
- Remove the given GHC version installed by ghcup
-
- USAGE:
- ${SCRIPT} rm [FLAGS] <VERSION>
-
- FLAGS:
- -h, --help Prints help information
- -f, --force Don't prompt user
-
- ARGS:
- <VERSION> E.g. \"8.4.3\" or \"8.6.1\"
- ")
- exit 1
- }
-
- # @FUNCTION: install_cabal_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup install-cabal' to STDERR
- # and exit the script with status code 1.
- install_cabal_usage() {
- (>&2 echo "ghcup-install-cabal
- Install the specified or a default cabal version
-
- USAGE:
- ${SCRIPT} install-cabal [FLAGS] [VERSION|TAG]
-
- FLAGS:
- -h, --help Prints help information
-
- ARGS:
- [VERSION|TAG] E.g. \"2.4.0.0\" or a tag
- like \"recommended\" or \"latest\"
-
- DISCUSSION:
- Installs the specified cabal-install version (or the default recommended)
- into \"${BIN_LOCATION}\", so it can be overwritten
- by later \"cabal new-install cabal-install\", which installs into
- \"~/.cabal/bin\". Make sure to set up your PATH appropriately, so
- the cabal installation takes precedence.
- ")
- exit 1
- }
-
- # @FUNCTION: compile_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup compile' to STDERR
- # and exit the script with status code 1.
- compile_usage() {
- (>&2 echo "ghcup-compile
- Compile and install the specified GHC version
-
- USAGE:
- ${SCRIPT} compile [FLAGS] <VERSION> <BOOTSTRAP-GHC>
-
- FLAGS:
- -h, --help Prints help information
- -f, --force Overwrite already existing installation
- -j, --jobs <n> How many jobs for compilation
- -c, --build-config <filepath> Use the given config file as build config
-
- ARGS:
- <VERSION> E.g. \"8.4.3\" or \"8.6.1\"
- <BOOTSTRAP-GHC> E.g. \"ghc-8.2.2\" or a full path
-
- DISCUSSION:
- Compiles and installs the specified GHC version into
- a self-contained \"~/.ghcup/ghc/<ghcver>\" directory
- and symlinks the ghc binaries to \"~/.ghcup/bin/<binary>-<ghcver>\".
-
- EXAMPLE:
- ghcup -v compile -f -j 4 8.4.2 ghc-8.2.2
- ")
- exit 1
- }
-
- # @FUNCTION: debug_info_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup debug-info' to STDERR
- # and exit the script with status code 1.
- debug_info_usage() {
- (>&2 echo "ghcup-debug-info
- Print debug info (e.g. detected system/distro)
-
- USAGE:
- ${SCRIPT} debug-info
-
- FLAGS:
- -h, --help Prints help information
-
- DISCUSSION:
- Prints debug information, e.g. detected system architecture,
- distribution, version, as well as script variables. This
- is mainly useful for debugging purposes.
- ")
- exit 1
- }
-
- # @FUNCTION: list_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup list' to STDERR
- # and exit the script with status code 1.
- list_usage() {
- (>&2 echo "ghcup-list
- Show available GHCs and other tools
-
- USAGE:
- ${SCRIPT} list
-
- FLAGS:
- -h, --help Prints help information
- -t, --tool <all|ghc|cabal-install> Tool to list versions for. Default is ghc only.
- -c, --show-criteria <installed|set> Show only installed or set tool versions
- -r, --raw-format Raw format, for machine parsing
-
- DISCUSSION:
- Prints tools (e.g. GHC and cabal-install) and their
- available/installed/set versions.
- ")
- exit 1
- }
-
- # @FUNCTION: changelog_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup changelog' to STDERR
- # and exit the script with status code 1.
- changelog_usage() {
- (>&2 echo "ghcup-changelog
- View the online changelog for the given GHC version
-
- USAGE:
- ${SCRIPT} changelog [FLAGS] [VERSION|TAG]
-
- FLAGS:
- -h, --help Prints help information
-
- ARGS:
- [VERSION|TAG] E.g. \"8.4.3\" or \"8.6.3\" or
- a tag like \"recommended\" or \"latest\"
- (default: discovers latest version)
-
- DISCUSSION:
- Opens the online changelog for the given GHC version via
- xdg-open.
- ")
- exit 1
- }
-
- # @FUNCTION: print_system_reqs_usage
- # @DESCRIPTION:
- # Print the help message for 'ghcup print-system-reqs' to STDERR
- # and exit the script with status code 1.
- print_system_reqs_usage() {
- (>&2 echo "ghcup-print-system-reqs
- Print an approximation of system requirements
-
- USAGE:
- ${SCRIPT} print-system-reqs
-
- FLAGS:
- -h, --help Prints help information
-
- DISCUSSION:
- Just prints an approximation of the system requirements
- for the 'recommended' GHC version and the 'latest' distro version
- you are on.
-
- Review this output carefully!
- ")
- exit 1
- }
-
-
-
-
- ###########################
- #--[ Utility functions ]--#
- ###########################
-
-
- # @FUNCTION: die
- # @USAGE: [msg]
- # @DESCRIPTION:
- # Exits the shell script with status code 2
- # and prints the given message in red to STDERR, if any.
- die() {
- (>&2 red_message "$1")
- exit 2
- }
-
- # @FUNCTION: edo
- # @USAGE: <command>
- # @DESCRIPTION:
- # Executes the given command. Also prints what
- # command that is (in blue) if verbosity is enabled.
- # Exits with status code 2 if the command failed.
- edo()
- {
- if ${VERBOSE} ; then
- printf "\\033[0;34m%s\\033[0m\\n" "$*" 1>&2
- fi
- "$@" || exit 2
- }
-
- # @FUNCTION: emake
- # @USAGE: [arguments]
- # @DESCRIPTION:
- # Wrapper around 'make', may call 'gmake' if it exists.
- emake() { # avoid re-checking for gmake
- if [ -n "${MAKE}" ] ; then
- # shellcheck disable=SC2086
- edo ${MAKE} "$@"
- else
- if command_exists gmake ; then
- MAKE="gmake"
- # shellcheck disable=SC2086
- edo ${MAKE} "$@"
- else
- MAKE="make"
- # shellcheck disable=SC2086
- edo ${MAKE} "$@"
- fi
- fi
- }
-
- # @FUNCTION: debug_message
- # @USAGE: <msg>
- # @DESCRIPTION:
- # Print a blue debug message if verbosity is enabled.
- debug_message() {
- if ${VERBOSE} ; then
- (>&2 printf "\\033[0;34m%s\\033[0m\\n" "$1")
- fi
- }
-
- # @FUNCTION: optionv
- # @USAGE: <arg1> [arg2]
- # @DESCRIPTION:
- # If verbosity is enabled, echo the first argument, otherwise
- # the second (if any).
- # @STDOUT: first or second argument
- optionv() {
- if ${VERBOSE} ; then
- echo "$1"
- else
- if [ -n "$2" ] ; then
- echo "$2"
- fi
- fi
- }
-
- # @FUNCTION: status_message
- # @USAGE: <msg>
- # @DESCRIPTION:
- # Print a green status message.
- status_message() {
- printf "\\033[0;32m%s\\033[0m\\n" "$1"
- }
-
- # @FUNCTION: warning_message
- # @USAGE: <msg>
- # @DESCRIPTION:
- # Print a yellow warning message.
- warning_message() {
- printf "\\033[1;33m%s\\033[0m\\n" "$1"
- }
-
- # @FUNCTION: red_message
- # @USAGE: <msg>
- # @DESCRIPTION:
- # Print a red message.
- red_message() {
- printf "\\033[0;31m%s\\033[0m\\n" "$1"
- }
-
- # @FUNCTION: command_exists
- # @USAGE: <command>
- # @DESCRIPTION:
- # Check if a command exists (no arguments).
- # @RETURNS: 0 if the command exists, non-zero otherwise
- command_exists() {
- [ -z "$1" ] && die "Internal error: no argument given to command_exists"
-
- command -V "$1" >/dev/null 2>&1
- return $?
- }
-
- # @FUNCTION: check_required_commands
- # @USAGE: [additional-commands]
- # @DESCRIPTION:
- # Check that all required commands for this script exist.
- # @STDOUT: The commands that do not exist
- # @RETURNS: 0 if all command exists, non-zero otherwise
- check_required_commands() {
- _missing_commands=
- mydistro=$(get_distro_alias "$(get_distro_name)")
-
- for com in "$@" awk uname basename tar gzip mktemp dirname ; do
- command_exists "${com}" || {
- _missing_commands="${_missing_commands} ${com}"
- }
- done
- unset com
-
- # darwin uses tar's built-in xz decompression
- if test "${mydistro}" != "darwin"; then
- command_exists xz || {
- _missing_commands="${_missing_commands} xz"
- }
- fi
-
- if [ -n "${_missing_commands}" ] ; then
- printf "%s" "${_missing_commands}"
- unset _missing_commands mydistro
- return 1
- else
- unset _missing_commands mydistro
- return 0
- fi
- }
-
- # @FUNCTION: get_distro_name
- # @DESCRIPTION:
- # Gets the current distro identifier following
- # https://unix.stackexchange.com/a/6348
- # (see also http://linuxmafia.com/faq/Admin/release-files.html)
- # @STDOUT: current distro identifier
- get_distro_name() {
- if [ -f /etc/os-release ]; then
- # freedesktop.org and systemd
- # shellcheck disable=SC1091
- . /etc/os-release
- printf "%s" "$NAME"
- elif command_exists lsb_release ; then
- # linuxbase.org
- printf "%s" "$(lsb_release -si)"
- elif [ -f /etc/lsb-release ]; then
- # For some versions of Debian/Ubuntu without lsb_release command
- # shellcheck disable=SC1091
- . /etc/lsb-release
- printf "%s" "$DISTRIB_ID"
- elif [ -f /etc/redhat-release ]; then
- case "$(cat /etc/redhat-release)" in
- # Older CentOS releases didn't have a /etc/centos-release file
- "CentOS release "*)
- printf "CentOS"
- ;;
- "CentOS Linux release "*)
- printf "CentOS Linux"
- ;;
- "Fedora release "*)
- printf "Fedora"
- ;;
- # Fallback to uname
- *)
- printf "%s" "$(uname -s)"
- ;;
- esac
- elif [ -f /etc/debian_version ]; then
- # Older Debian/Ubuntu/etc.
- printf "Debian"
- else
- # Fall back to uname, e.g. "Linux <version>", also works for BSD, etc.
- printf "%s" "$(uname -s)"
- fi
- }
-
- # @FUNCTION: get_distro_ver
- # @DESCRIPTION:
- # Gets the current distro version (if any) following
- # https://unix.stackexchange.com/a/6348
- # @STDOUT: current distro version, if any
- get_distro_ver() {
- if [ -f /etc/os-release ]; then
- # freedesktop.org and systemd
- # shellcheck disable=SC1091
- . /etc/os-release
- printf "%s" "$VERSION_ID"
- elif command_exists lsb_release ; then
- # linuxbase.org
- printf "%s" "$(lsb_release -sr)"
- elif [ -f /etc/lsb-release ]; then
- # For some versions of Debian/Ubuntu without lsb_release command
- # shellcheck disable=SC1091
- . /etc/lsb-release
- printf "%s" "$DISTRIB_RELEASE"
- elif [ -f /etc/redhat-release ]; then
- case "$(cat /etc/redhat-release)" in
- # NB: Older CentOS releases didn't have a /etc/centos-release file
- "CentOS release "*|"Fedora release "*)
- printf "%s" "$(awk 'NR==1 { split($3, a, "."); print a[1] }' /etc/redhat-release)"
- ;;
- "CentOS Linux release "*)
- printf "%s" "$(awk 'NR==1 { split($4, a, "."); print a[1] }' /etc/redhat-release)"
- ;;
- # Fallback to uname
- *)
- printf "%s" "$(uname -r)"
- ;;
- esac
- elif [ -f /etc/debian_version ]; then
- # Older Debian/Ubuntu/etc.
- printf "%s" "$(cat /etc/debian_version)"
- else
- case "$(uname -s)" in
- AIX)
- printf "%s" "$(uname -v)"
- ;;
- FreeBSD)
- # we only care about the major numeric version part left of
- # the '.' in "11.2-RELEASE".
- printf "%s" "$(uname -r | cut -d . -f 1)"
- ;;
- *)
- # Fall back to uname, e.g. "Linux <version>", also works for BSD, etc.
- printf "%s" "$(uname -r)"
- esac
- fi
- }
-
- # @FUNCTION: get_arch
- # @DESCRIPTION:
- # Gets the architecture following
- # https://unix.stackexchange.com/a/6348
- # Fails for any architecture that we don't know a GHC version for.
- # @STDOUT: current architecture
- get_arch() {
- myarch=$(uname -m)
-
- case "${myarch}" in
- x86_64|amd64)
- printf "x86_64" # or AMD64 or Intel64 or whatever
- ;;
- i*86)
- printf "i386" # or IA32 or Intel32 or whatever
- ;;
- *)
- case "$(uname -s)" in
- AIX)
- case "$(uname -p)" in
- powerpc)
- printf "powerpc"
- ;;
- *)
- die "Cannot figure out architecture on AIX (was: ${myarch})"
- ;;
- esac
- ;;
- *)
- die "Cannot figure out architecture (was: ${myarch})"
- ;;
- esac
- esac
-
- unset myarch
- }
-
- # @FUNCTION: try_download_url
- # @USAGE: <tool> <ver> <arch> <distro-ident> <file>
- # @DESCRIPTION:
- # Tries to get the download url of a tool with our
- # specified format for download urls (see ${META_DOWNLOAD_URL}").
- # STDOUT: the download url, if an appropriate was found
- try_download_url() {
- [ "$#" -lt 5 ] && die "Internal error: not enough arguments to try_download_url"
-
- tool=$1
- ver=$2
- arch=$3
- distro_ident=$4
- filename=$5
-
- awk "
- NF {
- split(\$4,a,\",\")
- if (\$1 == \"${tool}\" && \$2 == \"${ver}\" && \$3 == \"${arch}\") {
- for (i in a) if (a[i] == \"${distro_ident}\") {
- print \$5
- exit
- }
- }
- }" "${filename}" || die "awk failed!"
-
- unset tool ver arch distro_ident filename
- }
-
- # @FUNCTION: check_meta_file_version
- # @USAGE: <file> <metaver>
- # @DESCRIPTION:
- # Check that the given meta file has the same format version
- # as specified, otherwise die.
- check_meta_file_version() {
- { [ -z "$1" ] || [ -z "$2" ] ;} && die "Internal error: not enough arguments given to check_meta_file_version"
-
- mymetavar=$(awk "
- NR==1 {
- if (\$2 ~ \"fmt-version\") {
- {
- split(\$2,a,\"=\")
- print a[2]
- exit
- }
- }
- }" "$1")
-
- if [ "${mymetavar}" != "$2" ] ; then
- die "Unsupported meta file format, run: ${SCRIPT} upgrade"
- fi
-
- unset mymetavar
- }
-
- # @FUNCTION: get_download_url
- # @USAGE: <tool> <version> [os-overwrite]
- # @DESCRIPTION:
- # Gets the download url for the given tool and version
- # and the current distro and architecture (which it tries to discover).
- # This uses "${META_DOWNLOAD_URL}" for url discovery.
- # @STDOUT: download url or nothing if no appropriate was found
- get_download_url() {
- { [ -z "$1" ] || [ -z "$2" ] ;} && die "Internal error: not enough arguments given to get_download_url"
-
- mytool=$1
- myver=$2
- myarch=$(get_arch)
- [ -z "${myarch}" ] && die "failed to get architecture"
- if [ -n "$3" ] ; then
- mydistro=$(get_distro_alias "$3")
- else
- mydistro=$(get_distro_alias "$(get_distro_name)")
- fi
- mydistrover=$(get_distro_ver)
- meta_file="$(get_meta_download_file)"
- [ -z "${meta_file}" ] && die "failed to get meta file"
-
-
- # 1st try with full distro=ver
- url=$(try_download_url "${mytool}" "${myver}" "${myarch}" "${mydistro}=${mydistrover}" "${meta_file}")
- if [ -n "${url}" ] ; then
- printf "%s" "${url}"
- exit 0
- fi
-
- # 2nd try with just distro
- url=$(try_download_url "${mytool}" "${myver}" "${myarch}" "${mydistro}" "${meta_file}")
- if [ -n "${url}" ] ; then
- printf "%s" "${url}"
- exit 0
- fi
-
- # 3rd try with unknown
- url=$(try_download_url "${mytool}" "${myver}" "${myarch}" "unknown" "${meta_file}")
- if [ -n "${url}" ] ; then
- printf "%s" "${url}"
- exit 0
- fi
-
- unset mytool myver myarch mydistro mydistrover meta_file
- }
-
- # @FUNCTION: get_tool_ver_from_tag
- # @USAGE: <tool> <tag>
- # @DESCRIPTION:
- # Gets the tool version with the given tag (first match) from
- # "${META_VERSION_URL}".
- # STDOUT: the version, if any, or nothing
- get_tool_ver_from_tag() {
- { [ -z "$1" ] || [ -z "$2" ] ;} && die "Internal error: not enough arguments given to get_tool_ver_from_tag"
-
- mytool=$1
- mytag=$2
-
- meta_file="$(get_meta_version_file)"
- [ -z "${meta_file}" ] && die "failed to get meta file"
-
- awk "
- NF {
- if (\$1 == \"${mytool}\") {
- split(\$3,a,\",\");
- for (i in a) if (a[i] == \"${mytag}\") {
- print \$2
- exit
- }
- }
- }" "${meta_file}" || die "awk failed!"
-
- unset mytool mytag meta_file
- }
-
- # @FUNCTION: ghc_already_installed
- # @USAGE: <ghcversion>
- # @DESCRIPTION:
- # Checks whether the specified GHC version
- # has been installed by ghcup already.
- # @RETURN: 0 if GHC is already installed, 1 otherwise
- ghc_already_installed() {
- [ -z "$1" ] && die "Internal error: no argument given to ghc_already_installed"
-
- if [ -e "$(get_ghc_location "$1")" ] ; then
- return 0
- else
- return 1
- fi
- }
-
- # @FUNCTION: cabal_already_installed
- # @USAGE: <cabalversion>
- # @DESCRIPTION:
- # Checks whether the specified cabal version
- # has been installed by ghcup already.
- # @RETURN: 0 if cabal is already installed, 1 otherwise
- cabal_already_installed() {
- [ -z "$1" ] && die "Internal error: no argument given to cabal_already_installed"
-
- if [ -x "${BIN_LOCATION}/cabal" ] ; then
- if [ "$("${BIN_LOCATION}/cabal" --numeric-version)" = "$1" ] ; then
- return 0
- else
- return 1
- fi
- else
- return 1
- fi
- }
-
- # @FUNCTION: tool_already_installed
- # @USAGE: <tool> <cabalversion>
- # @DESCRIPTION:
- # Checks whether the specified tool and version
- # has been installed by ghcup already.
- # @RETURN: 0 if tool is already installed, 1 otherwise
- tool_already_installed() {
- if [ "$1" = "ghc" ] ; then
- ghc_already_installed "$2"
- return $?
- elif [ "$1" = "cabal-install" ] ; then
- cabal_already_installed "$2"
- return $?
- else
- return 1
- fi
- }
-
-
- # @FUNCTION: get_ghc_location
- # @USAGE: <ghcversion>
- # @DESCRIPTION:
- # Gets/prints the location where the specified GHC is or would be installed.
- # Doesn't check whether that directory actually exist. Use
- # 'ghc_already_installed' for that.
- # @STDOUT: ghc location
- get_ghc_location() {
- [ -z "$1" ] && die "Internal error: no argument given to get_ghc_location"
-
- myghcver=$1
- inst_location=${GHC_LOCATION}/${myghcver}
-
- printf "%s" "${inst_location}"
-
- unset myghcver inst_location
- }
-
- # @FUNCTION: download
- # @USAGE: <url>
- # @DESCRIPTION:
- # Downloads the given url as a file into the current directory.
- download() {
- [ -z "$1" ] && die "Internal error: no argument given to download"
- # shellcheck disable=SC2086
- edo ${DOWNLOADER} ${DOWNLOADER_OPTS} "$1"
- }
-
- # @FUNCTION: download_to_cache
- # @USAGE: <url>
- # @DESCRIPTION:
- # Downloads the given url as a file into the cache directory
- # and makes sure the file is deleted on failed/interrupted download.
- download_to_cache() {
- [ -z "$1" ] && die "Internal error: no argument given to download_to_cache"
-
- _dtc_download_url="$1"
- _dtc_download_tarball_name=$(basename "${_dtc_download_url}")
-
- rm_tarball() {
- if [ -f "${CACHE_LOCATION}/${_dtc_download_tarball_name}" ] ; then
- rm "${CACHE_LOCATION}/${_dtc_download_tarball_name}"
- fi
- }
-
- (
- trap 'rm_tarball' 2
- edo cd "${CACHE_LOCATION}"
- # shellcheck disable=SC2086
- edo ${DOWNLOADER} ${DOWNLOADER_OPTS} "${_dtc_download_url}"
- trap - 2
- ) || {
- rm_tarball
- die "Failed to download"
- }
-
- unset _dtc_download_tarball_name _dtc_download_url
- }
-
- # @FUNCTION: download_silent
- # @USAGE: <url>
- # @DESCRIPTION:
- # Downloads the given url as a file into the current directory, silent, unless
- # verbosity is on.
- download_silent() {
- [ -z "$1" ] && die "Internal error: no argument given to download"
-
- if ${VERBOSE} ; then
- # shellcheck disable=SC2086
- edo ${DOWNLOADER} ${DOWNLOADER_OPTS} "$1"
- else
- # shellcheck disable=SC2086
- edo ${DOWNLOADER} ${DOWNLOADER_OPTS} "$1" 1> /dev/null 2> /dev/null
- fi
- }
-
- # @FUNCTION: download_to_stdout
- # @USAGE: <url>
- # @DESCRIPTION:
- # Downloads the given url to stdout.
- download_to_stdout() {
- [ -z "$1" ] && die "Internal error: no argument given to download"
- # shellcheck disable=SC2086
- edo ${DOWNLOADER} ${DOWNLOADER_STDOUT_OPTS} "$1" 2> /dev/null
- }
-
- # @FUNCTION: mktempdir
- # @DESCRIPTION:
- # Makes a temporary directory.
- mktempdir() {
- mktemp_mydistro=$(get_distro_alias "$(get_distro_name)")
-
- if test "${mktemp_mydistro}" = "darwin"; then
- debug_message "mktemp -d -t ghcup.XXXXXXX"
- mktemp -d -t ghcup.XXXXXXX
- else
- debug_message "mktemp -d"
- mktemp -d
- fi
-
- unset mktemp_mydistro
- }
-
- # @FUNCTION: unpack
- # @USAGE: <tarball>
- # @DESCRIPTION:
- # Uncompresses and unpacks the given tarball if needed by discovering the
- # file extension.
- unpack() {
- [ -z "$1" ] && die "Internal error: no argument given to unpack"
-
- mydistro=$(get_distro_alias "$(get_distro_name)")
- filename=$1
- file_ext=${filename##*.}
-
- # this is for portability, since not all
- # distros have tar with compression detection
- # capability
- case "${file_ext}" in
- xz)
- if test "${mydistro}" = "darwin"; then
- debug_message "tar xf \"${filename}\""
- ( tar xf "${filename}" ) || die "unpacking failed!"
- else
- debug_message "xz -cd \"${filename}\" | tar -xf -"
- ( xz -cd "${filename}" | tar xf - ; ) || die "unpacking failed!"
- fi
- ;;
- gz)
- debug_message "gzip -cd \"${filename}\" | tar -xf -"
- ( gzip -cd "${filename}" | tar xf - ; ) || die "unpacking failed!"
- ;;
- bz2)
- debug_message "bzip2 -cd \"${filename}\" | tar -xf -"
- ( bzip2 -cd "${filename}" | tar xf - ; ) || die "unpacking failed!"
- ;;
- tar)
- edo tar xf "${filename}"
- ;;
- *)
- die "Unknown file extension: \"${file_ext}\""
- esac
-
- unset mydistro filename file_ext
- }
-
- # @FUNCTION: ask_for_confirmation
- # @USAGE: [confirmation-msg]
- # @DESCRIPTION:
- # Asks the user for confirmation and returns 0 for yes, 1 for no.
- # @RETURN: 0 if user confirmed, 1 otherwise
- ask_for_confirmation() {
- confirmation_msg=$1
-
- if [ -n "${confirmation_msg}" ] ; then
- printf "%s\\n(y/n and press Enter)\\n" "${confirmation_msg}"
- else
- printf "Confirm action: (y/n and press Enter)\\n"
- fi
- read -r answer
-
- if [ "${answer}" != "${answer#[Yy]}" ] ;then
- return 0
- else
- return 1
- fi
-
- unset confirmation_msg answer
- }
-
- # @FUNCTION: get_distro_alias
- # @USAGE: <distro name>
- # @DESCRIPTION:
- # For a given known distro name, return our internal
- # unique distro alias. E.g.:
- # Debian GNU/Linux -> debian
- # STDOUT: our internal distro alias
- get_distro_alias() {
- distro_name=$1
- distro_alias=unknown
-
- case "${distro_name}" in
- "Debian"|"Debian GNU/Linux"|"debian")
- distro_alias=debian
- ;;
- "Ubuntu"|"ubuntu")
- distro_alias=ubuntu
- ;;
- "Exherbo"|"exherbo")
- distro_alias=exherbo
- ;;
- "Fedora"|"fedora")
- distro_alias=fedora
- ;;
- "CentOS Linux"|"CentOS"|"centos"|"Red Hat Enterprise Linux"*)
- distro_alias=centos
- ;;
- "Alpine Linux"|"Alpine"|"alpine")
- distro_alias=alpine
- ;;
- "Linux Mint"|"LinuxMint"|"linuxmint")
- distro_alias=mint
- ;;
- "Amazon Linux AMI"|"amazonlinux")
- distro_alias=amazonlinux
- ;;
- "AIX"|"aix")
- distro_alias=aix
- ;;
- "FreeBSD"|"freebsd")
- distro_alias=freebsd
- ;;
- "Darwin"|"darwin")
- distro_alias=darwin
- ;;
- esac
-
- printf "%s" "${distro_alias}"
-
- unset distro_name distro_alias
- }
-
- # @FUNCTION: posix_realpath
- # @USAGE: <file>
- # @DESCRIPTION:
- # Portably gets the realpath and prints it to stdout.
- # This was initially inspired by
- # https://gist.github.com/tvlooy/cbfbdb111a4ebad8b93e
- # and
- # https://stackoverflow.com/a/246128
- #
- # If the file does not exist, just prints it appended to the current directory.
- # @STDOUT: realpath of the given file
- posix_realpath() {
- [ -z "$1" ] && die "Internal error: no argument given to posix_realpath"
- current_loop=0
- max_loops=50
- mysource=$1
-
- while [ -h "${mysource}" ]; do
- current_loop=$((current_loop+1))
- mydir="$( cd -P "$( dirname "${mysource}" )" > /dev/null 2>&1 && pwd )"
- mysource="$(readlink "${mysource}")"
- [ "${mysource%${mysource#?}}"x != '/x' ] && mysource="${mydir}/${mysource}"
-
- if [ ${current_loop} -gt ${max_loops} ] ; then
- (>&2 echo "${1}: Too many levels of symbolic links")
- break
- fi
- done
- mydir="$( cd -P "$( dirname "${mysource}" )" > /dev/null 2>&1 && pwd )"
-
- # TODO: better distinguish between "does not exist" and "permission denied"
- if [ -z "${mydir}" ] ; then
- (>&2 echo "${1}: Permission denied")
- else
- echo "${mydir%/}/$(basename "${mysource}")"
- fi
-
- unset current_loop max_loops mysource mydir
- }
-
-
- # @FUNCTION: get_meta_version_file
- # @DESCRIPTION:
- # Downloads the META_VERSION_URL
- # in case it hasn't been downloaded
- # during the execution of this script yet
- # and checks the format version matches
- # the expected one.
- # @STDOUT: file location
- get_meta_version_file() {
- meta_file_name="$(basename "${META_VERSION_URL}")"
- meta_filepath="${CACHE_LOCATION}/${meta_file_name}"
-
- if [ ! -f "${meta_filepath}" ] ; then
- (
- edo cd "${CACHE_LOCATION}"
- download_silent "${META_VERSION_URL}"
- ) || die "downloading failed"
- fi
-
- check_meta_file_version "${meta_filepath}" "${META_VERSION_FORMAT}"
-
- printf "%s" "${meta_filepath}"
-
- unset meta_file_name meta_filepath
- }
-
-
- # @FUNCTION: get_meta_download_file
- # @DESCRIPTION:
- # Downloads the META_DOWNLOAD_URL
- # in case it hasn't been downloaded
- # during the execution of this script yet
- # and checks the format version matches
- # the expected one.
- # @STDOUT: file location
- get_meta_download_file() {
- meta_file_name="$(basename "${META_DOWNLOAD_URL}")"
- meta_filepath="${CACHE_LOCATION}/${meta_file_name}"
-
- if [ ! -f "${meta_filepath}" ] ; then
- (
- edo cd "${CACHE_LOCATION}"
- download_silent "${META_DOWNLOAD_URL}"
- ) || die "downloading failed!"
- fi
-
- check_meta_file_version "${meta_filepath}" "${META_DOWNLOAD_FORMAT}"
-
- printf "%s" "${CACHE_LOCATION}/${meta_file_name}"
-
- unset meta_file_name meta_filepath
- }
-
- # @FUNCTION: known_tool_versions
- # @USAGE: <tool>
- # @DESCRIPTION:
- # Prints the known tool versions from
- # META_VERSION_URL.
- # @STDOUT: known ghc versions
- known_tool_versions() {
- [ -z "$1" ] && die "Internal error: no argument given to posix_realpath"
-
- mytool=$1
- meta_file="$(get_meta_version_file)"
- [ -z "${meta_file}" ] && die "failed to get meta file"
-
- awk "
- NF {
- if (\$1 == \"${mytool}\") {
- print \$2
- }
- }" "${meta_file}" || die "awk failed!"
-
- unset mytool meta_file
- }
-
-
- # @FUNCTION: known_tool_tags
- # @USAGE: <tool>
- # @DESCRIPTION:
- # Prints the known tool tags from
- # META_VERSION_URL.
- # @STDOUT: known tool tags
- known_tool_tags() {
- [ -z "$1" ] && die "Internal error: no argument given to known_tool_tags"
-
- mytool=$1
- meta_file="$(get_meta_version_file)"
- [ -z "${meta_file}" ] && die "failed to get meta file"
-
- awk "
- NF {
- if (\$1 == \"${mytool}\") {
- split(\$3,a,\",\");
- for (i in a) {
- print a[i]
- }
- }
- }" "${meta_file}" | sort -u || die "awk failed!"
-
- unset mytool meta_file
- }
-
- # @FUNCTION: array_contains
- # @USAGE: <element> <array>
- # @DESCRIPTION:
- # Checks whether the given elements
- # is in the array.
- # @RETURNS: returns 0 if the element is in the array, 1 otherwise
- array_contains() {
- { [ -z "$1" ] || [ -z "$2" ] ;} && die "Internal error: not enough arguments given to array_contains"
-
- element=$1
- array=$2
-
- for e in ${array} ; do
- if [ "${e}" = "${element}" ] ; then
- unset e element array
- return 0
- fi
- done
-
- unset e element array
- return 1
- }
-
- # @FUNCTION: show_ghc_installed
- # @DESCRIPTION:
- # Prints the currently selected GHC only as version string.
- # @STDOUT: current GHC version
- show_ghc_installed() {
- current_ghc="${BIN_LOCATION}/ghc"
- real_ghc=$(posix_realpath "${current_ghc}")
-
- if [ -L "${current_ghc}" ] ; then # is symlink
- if [ -f "${real_ghc}" ] ; then # exists (posix_realpath was called)
- real_ghc="$(basename "${real_ghc}" | sed 's#ghc-##')"
- printf "%s" "${real_ghc}"
- else # is a broken symlink
- red_message "broken symlink"
- fi
- fi
-
- unset real_ghc current_ghc
- }
-
- # @FUNCTION: show_cabal_installed
- # @DESCRIPTION:
- # Prints the currently selected cabal only as version string.
- # @STDOUT: current cabal version
- show_cabal_installed() {
- if [ -x "${BIN_LOCATION}/cabal" ] ; then
- "${BIN_LOCATION}/cabal" --numeric-version
- fi
- }
-
-
- # @FUNCTION: get_full_ghc_ver
- # @USAGE: <ghcmajorversion>
- # @DESCRIPTION:
- # Get the latest full GHC version .
- get_full_ghc_ver() {
- [ -z "$1" ] && die "Internal error: no argument given to get_full_ghc_ver"
-
- mymajorghcver=$1
- latest_ghc=0
-
- for current_ghc in "${BIN_LOCATION}/ghc-${mymajorghcver}."* ; do
- [ -f "${current_ghc}" ] || break
- real_ghc=$(posix_realpath "${current_ghc}")
- real_ghc="$(basename "${real_ghc}" | sed 's#ghc-##')"
- if [ "$(expr "${real_ghc}" \> "${latest_ghc}")" = 1 ] ; then
- latest_ghc=${real_ghc}
- fi
- done
-
- if [ "${latest_ghc}" != 0 ] ; then
- printf "%s" "${latest_ghc}"
- fi
-
- unset mymajorghcver latest_ghc real_ghc current_ghc
- }
-
- # @FUNCTION: set_ghc_major
- # @USAGE: <ghcversion>
- # @DESCRIPTION:
- # Sets a ghc-x.y major version to the latest ghc-x.y.z if any is installed.
- set_ghc_major() {
- [ -z "$1" ] && die "Internal error: no argument given to set_ghc_major"
-
- full_ghc_ver="$(get_full_ghc_ver "${1%.*}")"
-
- if [ -z "${full_ghc_ver}" ] ; then
- die "Could not set GHC major symlink"
- fi
- set_ghc "${full_ghc_ver}" "-${1%.*}"
-
- unset full_ghc_ver
- }
-
-
-
-
- ############################
- #--[ Subcommand install ]--#
- ############################
-
-
- # @FUNCTION: install_ghc
- # @USAGE: <ghcversion> [os-overwrite]
- # @DESCRIPTION:
- # Installs the given ghc version with a lot of side effects.
- install_ghc() {
- [ -z "$1" ] && die "Internal error: no argument given to install_ghc"
-
- myghcver=$1
- inst_location=$(get_ghc_location "$1")
- [ -z "${inst_location}" ] && die "failed to get install location"
- download_url=$(get_download_url "ghc" "${myghcver}" "$2")
- if [ -z "${download_url}" ] ; then
- die "Could not find an appropriate download for the requested GHC-${myghcver} on your system! Please report a bug at ${BUG_URL}"
- fi
- download_tarball_name=$(basename "${download_url}")
- first_install=true
-
-
- status_message "Installing GHC-${myghcver} for $(if [ -n "$2" ] ; then echo "$2" ; else get_distro_name ; fi) on architecture $(get_arch)"
-
- if ghc_already_installed "${myghcver}" ; then
- if ${FORCE} ; then
- echo "GHC already installed in ${inst_location}, overwriting!"
- else
- warning_message "GHC already installed in ${inst_location}, use --force to overwrite"
- exit 0
- fi
- first_install=false
- fi
-
- tmp_dir=$(mktempdir)
- { [ -z "${tmp_dir}" ] || ! [ -d "${tmp_dir}" ] ; } && die "Failed to create temporary directory"
- (
- if ${CACHING} ; then
- if [ ! -f "${CACHE_LOCATION}/${download_tarball_name}" ] ; then
- download_to_cache "${download_url}"
- fi
- edo cd "${tmp_dir}"
- unpack "${CACHE_LOCATION}/${download_tarball_name}"
- else
- edo cd "${tmp_dir}"
- download "${download_url}"
- unpack "${download_tarball_name}"
- fi
-
- edo cd "./ghc-${myghcver}"
-
- debug_message "Installing GHC into ${inst_location}"
-
- edo ./configure --prefix="${inst_location}"
- emake install
-
- # clean up
- edo cd ..
- [ -f "${tmp_dir}/${download_tarball_name}" ] && rm "${tmp_dir}/${download_tarball_name}"
- [ -e "${tmp_dir}/ghc-${myghcver}" ] && rm -r "${tmp_dir}/ghc-${myghcver}"
- ) || {
- [ -f "${tmp_dir}/${download_tarball_name}" ] && rm "${tmp_dir}/${download_tarball_name}"
- [ -e "${tmp_dir}/ghc-${myghcver}" ] && rm -r "${tmp_dir}/ghc-${myghcver}"
-
- if ${first_install} ; then
- [ -e "${inst_location}" ] && rm -r "${inst_location}"
- else
- warning_message "GHC force installation failed. The install might be broken."
- warning_message "Consider running: ghcup rm ${myghcver}"
- fi
-
- die "Failed to install, consider updating this script via: ${SCRIPT} upgrade"
- }
-
- for f in "${inst_location}"/bin/*-"${myghcver}" ; do
- [ -f "${f}" ] || die "Something went wrong, ${f} does not exist!"
- fn=$(basename "${f}")
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}/bin/${fn}" "${BIN_LOCATION}/${fn}"
- unset fn
- done
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/runhaskell "${BIN_LOCATION}/runhaskell-${myghcver}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/hsc2hs "${BIN_LOCATION}/hsc2hs-${myghcver}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/hp2ps "${BIN_LOCATION}/hp2ps-${myghcver}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/hpc "${BIN_LOCATION}/hpc-${myghcver}"
- if [ -f "${inst_location}/bin/haddock" ] ; then
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/haddock "${BIN_LOCATION}/haddock-${myghcver}"
- fi
-
- status_message "Done installing, run \"ghci-${myghcver}\" or set up your current GHC via: ${SCRIPT} set ${myghcver}"
-
- unset inst_location f download_url download_tarball_name first_install tmp_dir
-
- set_ghc_major "${myghcver}"
-
- unset myghcver
- }
-
-
-
- ########################
- #--[ Subcommand set ]--#
- ########################
-
-
- # @FUNCTION: set_ghc
- # @USAGE: <ghcversion> [target-suffix]
- # @DESCRIPTION:
- # Sets the current ghc version by creating symlinks.
- set_ghc() {
- [ -z "$1" ] && die "Internal error: no argument given to set_ghc"
-
- myghcver=$1
- target_suffix=$2
- inst_location=$(get_ghc_location "$1")
- [ -z "${inst_location}" ] && die "failed to get install location"
-
- [ -e "${inst_location}" ] || die "GHC ${myghcver} not installed yet, use: ${SCRIPT} install ${myghcver}"
-
- status_message "Setting GHC${target_suffix} to ${myghcver}"
-
- for f in "${inst_location}"/bin/*-"${myghcver}" ; do
- [ -f "${f}" ] || die "Something went wrong, ${f} does not exist!"
- source_fn=$(basename "${f}")
- target_fn="$(echo "${source_fn}" | sed "s#-${myghcver}##")${target_suffix}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}/bin/${source_fn}" "${BIN_LOCATION}/${target_fn}"
- unset source_fn target_fn
- done
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf "runghc${target_suffix}" "${BIN_LOCATION}/runhaskell${target_suffix}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf "hsc2hs-${myghcver}" "${BIN_LOCATION}/hsc2hs${target_suffix}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf "hp2ps-${myghcver}" "${BIN_LOCATION}/hp2ps${target_suffix}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf "hpc-${myghcver}" "${BIN_LOCATION}/hpc${target_suffix}"
- # not all bindists install haddock...
- if [ -f "${inst_location}/bin/haddock" ] ; then
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf "haddock-ghc${target_suffix}" "${BIN_LOCATION}/haddock${target_suffix}"
- fi
- if [ -z "${target_suffix}" ] && [ -d "${inst_location}/share" ] ; then
- # Make sure we don't link "${BIN_LOCATION}/../share/share".
- # POSIX doesn't allow '-T' for 'ln'.
- if [ -e "${BIN_LOCATION}/../share" ] ; then
- edo rm "${BIN_LOCATION}/../share"
- fi
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ghc/"${myghcver}"/share "${BIN_LOCATION}/../share"
- fi
-
- status_message "Done"
-
- unset myghcver inst_location f target_suffix
- }
-
-
-
-
- ############################
- #--[ Subcommand upgrade ]--#
- ############################
-
-
- # @FUNCTION: upgrade
- # @USAGE: <install-location>
- # @DESCRIPTION:
- # Downloads the latest version of this script and places it into
- # the given directory.
- upgrade() {
- target_location=$1
-
- [ -e "${target_location}" ] || die "Destination \"${target_location}\" does not exist, cannot update script"
-
- status_message "Updating ${SCRIPT}"
-
- (
- edo cd "$(mktempdir)"
- download "${SCRIPT_UPDATE_URL}"
- edo chmod +x ghcup
- edo mv -f ghcup "${target_location}"/ghcup
-
- ) || die "failed to install"
-
- status_message "Done"
-
- unset target_location
- }
-
-
-
-
- #######################
- #--[ Subcommand rm ]--#
- #######################
-
-
- # @FUNCTION: rm_ghc
- # @USAGE: <ghcversion>
- # @DESCRIPTION:
- # Removes the given GHC version installed by ghcup.
- rm_ghc() {
- [ -z "$1" ] && die "Internal error: no argument given to rm_ghc"
-
- myghcver=$1
- inst_location=$(get_ghc_location "${myghcver}")
-
- [ -z "${myghcver}" ] && die "We are paranoid, ghcver not set"
-
- if ghc_already_installed "${myghcver}" ; then
- [ -z "${inst_location}" ] && die "internal error: inst_location empty!"
-
- if ! ${FORCE} ; then
- if ! ask_for_confirmation "Really removing ${myghcver}? This will also recursively remove the following directory (please double-check): \"${inst_location}\"" ; then
- warning_message "Not removing GHC..."
- return 0
- fi
- fi
-
- for f in "${BIN_LOCATION}"/*-"${myghcver}" ; do
- # https://tanguy.ortolo.eu/blog/article113/test-symlink
- [ ! -e "${f}" ] && [ ! -h "${f}" ] && {
- warning_message "No existing symlinks for ${myghcver} in ${BIN_LOCATION}, skipping"
- break
- }
- edo rm "${f}"
- done
-
- edo rm -r "${inst_location}"
-
- status_message "Successfully removed GHC ${myghcver}."
-
- # Only run set_ghc_major if there is at least one 8.6.x version left for 8.6.
- if [ -n "$(get_full_ghc_ver "${myghcver%.*}")" ] ; then
- set_ghc_major "${myghcver}"
- fi
-
- if [ -h "${BIN_LOCATION}/ghc-${myghcver%.*}" ] && [ ! -e "${BIN_LOCATION}/ghc-${myghcver%.*}" ] ; then
- # TODO: known_tools is not very robust, but we want to avoid accidentially deleting
- # unrelated things (even if those are dangling symlinks)
- known_tools="ghc ghci ghc-pkg haddock haddock-ghc runghc runhaskell hp2ps hpc hsc2hs"
- # remove dangling symlinks for ghc, ghci, ...
- for t in ${known_tools} ; do
- if [ -h "${BIN_LOCATION}/${t}-${myghcver%.*}" ] && [ ! -e "${BIN_LOCATION}/${t}-${myghcver%.*}" ] ; then
- edo rm "${BIN_LOCATION}/${t}-${myghcver%.*}"
- fi
- done
- unset t known_tools
- fi
-
- if [ -h "${BIN_LOCATION}/ghc" ] && [ ! -e "${BIN_LOCATION}/ghc" ] ; then
- warning_message "Currently active GHC is a dangling symlink, removing..."
-
- # TODO: known_tools is not very robust, but we want to avoid accidentially deleting
- # unrelated things (even if those are dangling symlinks)
- known_tools="ghc ghci ghc-pkg haddock haddock-ghc runghc runhaskell hp2ps hpc hsc2hs"
- # remove dangling symlinks for ghc, ghci, ...
- for t in ${known_tools} ; do
- if [ -h "${BIN_LOCATION}/${t}" ] && [ ! -e "${BIN_LOCATION}/${t}" ] ; then
- edo rm "${BIN_LOCATION}/${t}"
- fi
- done
- unset t known_tools
- # remove dangling symlink to share directory
- if [ -h "${BIN_LOCATION}/../share" ] && [ ! -e "${BIN_LOCATION}/../share" ] ; then
- edo rm "${BIN_LOCATION}/../share"
- fi
-
- warning_message "Done."
- warning_message "You may now want to set currently active GHC to a different version via:"
- warning_message " ghcup set <ghcver>"
- fi
- else
- warning_message "${myghcver} doesn't appear to be installed, skipping"
- fi
-
- unset myghcver inst_location f
- }
-
- ############################
- #--[ Subcommand install ]--#
- ############################
-
-
- # @FUNCTION: install_cabal
- # @USAGE: <cabalversion> [os-overwrite]
- # @DESCRIPTION:
- # Installs the given cabal version.
- install_cabal() {
- [ -z "$1" ] && die "Internal error: no argument given to install_cabal"
-
- mycabalver=$1
- myarch=$(get_arch)
- [ -z "${myarch}" ] && die "failed to get architecture"
- inst_location=$BIN_LOCATION
- download_url=$(get_download_url "cabal-install" "${mycabalver}" "$2")
- download_tarball_name=$(basename "${download_url}")
-
- if [ -z "${download_url}" ] ; then
- die "Could not find an appropriate download for the requested cabal-install-${mycabalver} on your system! Please report a bug at ${BUG_URL}"
- fi
-
- status_message "Installing cabal-install-${mycabalver} for $(if [ -n "$2" ] ; then echo "$2" ; else get_distro_name ; fi) on architecture $(get_arch)"
-
- edo mkdir -p "${inst_location}"
-
- tmp_dir=$(mktempdir)
- { [ -z "${tmp_dir}" ] || ! [ -d "${tmp_dir}" ] ; } && die "Failed to create temporary directory"
- (
- if ${CACHING} ; then
- if [ ! -f "${CACHE_LOCATION}/${download_tarball_name}" ] ; then
- download_to_cache "${download_url}"
- fi
- edo cd "${tmp_dir}"
- unpack "${CACHE_LOCATION}/${download_tarball_name}"
- else
- edo cd "${tmp_dir}"
- download "${download_url}"
- unpack "${download_tarball_name}"
- fi
-
- edo mv -f cabal "${inst_location}"/cabal
- if [ -f "${tmp_dir}/${download_tarball_name}" ] ; then
- rm "${tmp_dir}/${download_tarball_name}"
- fi
- ) || die "Failed to install cabal-install"
-
- status_message "Successfully installed cabal-install into"
- status_message " ${BIN_LOCATION}"
- status_message ""
-
- unset mycabalver myarch inst_location download_url download_tarball_name tmp_dir
- }
-
- # @FUNCTION: compile_ghc
- # @USAGE: <ghcversion> <bootstrap-ghc> [build.mk]
- # @DESCRIPTION:
- # Compile and installs the given GHC version with the
- # specified GHC bootstrap version.
- # Can additionally take a custom file that will be used
- # as build configuration.
- compile_ghc() {
- { [ -z "$1" ] || [ -z "$2" ] ;} && die "Internal error: not enough arguments given to compile_ghc"
-
- myghcver=$1
- bootstrap_ghc=$2
- inst_location=$(get_ghc_location "$1")
- [ -z "${inst_location}" ] && die "failed to get install location"
- download_url="https://downloads.haskell.org/~ghc/${myghcver}/ghc-${myghcver}-src.tar.xz"
- download_tarball_name=$(basename "${download_url}")
-
- if [ -n "$3" ] ; then
- case "$3" in
- /*) build_config=$3 ;;
- *) build_config="$(pwd)/$3" ;;
- esac
- [ -f "${build_config}" ] || die "specified build config \"${build_config}\" file does not exist!"
- fi
-
- if ghc_already_installed "${myghcver}" ; then
- if ${FORCE} ; then
- echo "GHC already installed in ${inst_location}, overwriting!"
- else
- die "GHC already installed in ${inst_location}, use --force to overwrite"
- fi
- fi
-
- status_message "Compiling GHC for version ${myghcver} from source"
- tmp_dir=$(mktempdir)
- { [ -z "${tmp_dir}" ] || ! [ -d "${tmp_dir}" ] ; } && die "Failed to create temporary directory"
- (
- if ${CACHING} ; then
- if [ ! -f "${CACHE_LOCATION}/${download_tarball_name}" ] ; then
- download_to_cache "${download_url}"
- fi
- edo cd "${tmp_dir}"
- unpack "${CACHE_LOCATION}/${download_tarball_name}"
- else
- edo cd "${tmp_dir}"
- download "${download_url}"
- unpack "${download_tarball_name}"
- fi
-
- edo cd "./ghc-${myghcver}"
-
- if [ -n "${build_config}" ] ; then
- edo cat "${build_config}" > mk/build.mk
- else
- cat <<-EOF > mk/build.mk || die
- V=0
- BUILD_MAN = NO
- BUILD_SPHINX_HTML = NO
- BUILD_SPHINX_PDF = NO
- HADDOCK_DOCS = YES
- GhcWithLlvmCodeGen = YES
- EOF
- fi
-
-
- edo ./boot
- if [ "$(echo "${myghcver}" | awk -F. '{printf"%d%03d",$1,$2;}')" -ge 8008 ]; then
- GHC=$(command -v "${bootstrap_ghc}") edo ./configure --prefix="${inst_location}"
- else
- edo ./configure --prefix="${inst_location}" --with-ghc="${bootstrap_ghc}"
- fi
- emake -j${JOBS}
- emake install
-
- # clean up
- edo cd ..
- [ -f "${tmp_dir}/${download_tarball_name}" ] && rm "${tmp_dir}/${download_tarball_name}"
- [ -e "${tmp_dir}/ghc-${myghcver}" ] && rm -r "${tmp_dir}/ghc-${myghcver}"
- ) || {
- [ -f "${tmp_dir}/${download_tarball_name}" ] && rm "${tmp_dir}/${download_tarball_name}"
- [ -e "${tmp_dir}/ghc-${myghcver}" ] && rm -r "${tmp_dir}/ghc-${myghcver}"
- die "Failed to install, consider updating this script via:
- ${SCRIPT} upgrade
- Also check https://ghc.haskell.org/trac/ghc/wiki/Building/Preparation/Linux for build requirements and follow the instructions."
- }
-
- for f in "${inst_location}"/bin/*-"${myghcver}" ; do
- [ -f "${f}" ] || die "Something went wrong, ${f} does not exist!"
- fn=$(basename "${f}")
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}/bin/${fn}" "${BIN_LOCATION}/${fn}"
- unset fn
- done
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/runhaskell "${BIN_LOCATION}/runhaskell-${myghcver}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/hsc2hs "${BIN_LOCATION}/hsc2hs-${myghcver}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/hp2ps "${BIN_LOCATION}/hp2ps-${myghcver}"
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/hpc "${BIN_LOCATION}/hpc-${myghcver}"
- if [ -f "${inst_location}/bin/haddock" ] ; then
- # shellcheck disable=SC2046
- edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/haddock "${BIN_LOCATION}/haddock-${myghcver}"
- fi
-
- status_message "Done installing, run \"ghci-${myghcver}\" or set up your current GHC via: ${SCRIPT} set ${myghcver}"
-
- unset bootstrap_ghc inst_location f download_url download_tarball_name tmp_dir
-
- set_ghc_major "${myghcver}"
-
- unset myghcver
- }
-
-
- ###############################
- #--[ Subcommand debug-info ]--#
- ###############################
-
-
- # @FUNCTION: print_debug_info
- # @DESCRIPTION:
- # Print debug info (e.g. detected system/distro).
- print_debug_info() {
- echo "Script version: ${VERSION}"
- echo
- echo "Script variables:"
- echo " GHC install location: ${GHC_LOCATION}"
- echo " Binary install location: ${BIN_LOCATION}"
- echo " Tarball cache location: ${CACHE_LOCATION}"
- echo " Downloader: ${DOWNLOADER} ${DOWNLOADER_OPTS} <url>"
- echo " Script update url: ${SCRIPT_UPDATE_URL}"
- echo " GHC download baseurl: ${GHC_DOWNLOAD_BASEURL}"
- echo " Meta download url ${META_DOWNLOAD_URL}"
- echo " Meta download format ${META_DOWNLOAD_FORMAT}"
- echo " Meta version url ${META_VERSION_URL}"
- echo " Meta version format ${META_VERSION_FORMAT}"
- echo
- echo "Detected system information:"
- echo " Architecture: $(get_arch)"
- echo " Distribution: $(get_distro_name)"
- echo " Distro alias: $(get_distro_alias "$(get_distro_name)")"
- echo " Distro version: $(get_distro_ver)"
- }
-
-
- #########################
- #--[ Subcommand list ]--#
- #########################
-
-
- # @FUNCTION: list
- # @USAGE: <tool> <raw-format> <criteria>
- # @DESCRIPTION:
- # List available tools and their versions from upstream.
- list() {
- mytool=$1
- raw_format=$2
- criteria=$3
-
- meta_file="$(get_meta_version_file)"
- [ -z "${meta_file}" ] && die "failed to get meta file"
-
- if ! ${raw_format} ; then
- printf "\\033[1;32m%s\\033[0m\\n" "Available versions:"
- fi
-
- lines=$(
- if [ "${mytool}" = "all" ] ; then
- awk "
- NF {
- if (\$1 != \"#\") {
- print \$1 \"\\t\" \$2 \"\\t\" \$3
- }
- }" "${meta_file}" || die "awk failed!"
- else
- awk "
- NF {
- if (\$1 == \"${mytool}\") {
- print \$1 \"\\t\" \$2 \"\\t\" \$3
- }
- }" "${meta_file}" || die "awk failed!"
- fi
- )
-
- _print_me() {
- if ${raw_format} ; then
- printf "%s\\n" "$1"
- else
- if [ "$2" = "available" ] ; then
- printf "\\033[0;32m\342\234\224\\033[0m %s\\n" "$1"
- elif [ "$2" = "set" ] ; then
- printf "\\033[0;32m\342\234\224 \\033[0;34m%s\\033[0m\\n" "$1"
- elif [ "$2" = "unavailable" ] ; then
- printf "\\033[0;31m\342\234\227\\033[0m %s\\n" "$1"
- fi
- fi
- }
-
- if [ -z "${lines}" ] ; then
- (>&2 echo "Nothing found for tool ${mytool}")
- return
- fi
-
-
- echo "$lines" | while read -r l; do
- tool=$(echo "${l}" | cut -f1)
- version=$(echo "${l}" | cut -f2)
-
- if [ "${criteria}" = "set" ] ; then
- if [ "${tool}" = "ghc" ] && [ "${version}" = "$(show_ghc_installed)" ] ; then
- _print_me "${l}" "set"
- fi
-
- if [ "${tool}" = "cabal-install" ] && [ "${version}" = "$(show_cabal_installed)" ] ; then
- _print_me "${l}" "set"
- fi
- else
- if tool_already_installed "${tool}" "${version}" ; then
- if [ "${tool}" = "ghc" ] && [ "${version}" = "$(show_ghc_installed)" ] ; then
- _print_me "${l}" "set"
- elif [ "${tool}" = "cabal-install" ] && [ "${version}" = "$(show_cabal_installed)" ] ; then
- _print_me "${l}" "set"
- else
- _print_me "${l}" "available"
- fi
- else
- if [ "${criteria}" != "installed" ] ; then
- _print_me "${l}" "unavailable"
- fi
- fi
- fi
- done
-
- unset mytool meta_file l lines tool version raw_format installed_only criteria
- }
-
-
- ##############################
- #--[ Subcommand changelog ]--#
- ##############################
-
-
- # @FUNCTION: changelog_url
- # @USAGE: <ghcversion>
- # @DESCRIPTION:
- # Print the changelog url for the given GHC version to stdout.
- # @STDOUT: the changelog url
- changelog_url() {
- [ -z "$1" ] && die "Internal error: no argument given to changelog"
-
- printf "https://downloads.haskell.org/~ghc/%s/docs/html/users_guide/%s-notes.html" "$1" "$1"
- }
-
-
- # @FUNCTION: changelog
- # @USAGE: <ghcversion>
- # @DESCRIPTION:
- # Opens the changelog for the given ghc version via xdg-open.
- changelog() {
- [ -z "$1" ] && die "Internal error: no argument given to changelog"
-
- url=$(changelog_url "$1")
-
- xdg-open "${url}" || die "failed to xdg-open the following url: ${url}"
-
- unset url
- }
-
-
- ######################################
- #--[ Subcommand print-system-reqs ]--#
- ######################################
-
-
- # @FUNCTION: system_reqs_url
- # @USAGE: <distro-alias>
- # @DESCRIPTION:
- # Mapping of distro-alias to system requirements URL.
- system_reqs_url() {
- [ -z "$1" ] && die "Internal error: no argument given to system_reqs_url"
-
- case "$1" in
- "alpine")
- printf "%s/.requirements/ghc/alpine" "${BASE_DOWNLOAD_URL}"
- ;;
- "debian"|"ubuntu")
- printf "%s/.requirements/ghc/ubuntu" "${BASE_DOWNLOAD_URL}"
- ;;
- "darwin")
- printf "%s/.requirements/ghc/darwin" "${BASE_DOWNLOAD_URL}"
- ;;
- *)
- printf "%s/.requirements/ghc/default" "${BASE_DOWNLOAD_URL}"
- ;;
- esac
- }
-
-
- # @FUNCTION: print_system_reqs
- # @DESCRIPTION:
- # Print the system requirements (approximation).
- print_system_reqs() {
- mydistro=$(get_distro_alias "$(get_distro_name)")
- reqs_url=$(system_reqs_url "${mydistro}")
-
- download_to_stdout "${reqs_url}"
-
- unset mydistro reqs_url
- }
-
- #######################
- #--[ Sanity checks ]--#
- #######################
-
-
- if [ -z "${GHCUP_INSTALL_BASE_PREFIX}" ] ; then
- die "GHCUP_INSTALL_BASE_PREFIX empty, cannot operate"
- fi
-
- if [ ! -d "${GHCUP_INSTALL_BASE_PREFIX}" ] ; then
- die "${GHCUP_INSTALL_BASE_PREFIX} does not exist"
- fi
-
-
-
-
- ##############################################
- #--[ Command line parsing and entry point ]--#
- ##############################################
-
- [ $# -lt 1 ] && usage
-
- while [ $# -gt 0 ] ; do
- case $1 in
- -v|--verbose)
- VERBOSE=true
- shift 1
- if [ $# -lt 1 ] ; then
- usage
- fi
- ;;
- -V|--version)
- printf "%s\\n" "${VERSION}"
- exit 0;;
- --list-commands)
- echo "changelog
- compile
- debug-info
- install
- install-cabal
- list
- print-system-reqs
- rm
- set
- upgrade"
- exit 0;;
- -h|--help)
- usage;;
- -w|--wget)
- DOWNLOADER="wget"
- DOWNLOADER_OPTS=""
- DOWNLOADER_STDOUT_OPTS="-qO-"
- shift 1
- if [ $# -lt 1 ] ; then
- usage
- fi
- ;;
- -c|--cache)
- CACHING=true
- shift 1
- if [ $# -lt 1 ] ; then
- usage
- fi
- ;;
- -o|--os) MY_OS=$2
- shift 2;;
-
- *) ## startup tasks ##
-
- edo mkdir -p "${INSTALL_BASE}"
- edo mkdir -p "${BIN_LOCATION}"
- edo mkdir -p "${CACHE_LOCATION}"
-
- # clean up old meta files
- if [ -f "${CACHE_LOCATION}/$(basename "${META_VERSION_URL}")" ] ; then
- edo rm "${CACHE_LOCATION}/$(basename "${META_VERSION_URL}")"
- fi
- if [ -f "${CACHE_LOCATION}/$(basename "${META_DOWNLOAD_URL}")" ] ; then
- edo rm "${CACHE_LOCATION}/$(basename "${META_DOWNLOAD_URL}")"
- fi
-
- # check for available commands
- missing_commands="$(check_required_commands ${DOWNLOADER})"
- if [ -n "${missing_commands}" ] ; then
- die "Following commands are required, but missing, please install: ${missing_commands}"
- fi
- unset missing_commands
- case $1 in
- install)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) install_usage;;
- -f|--force) FORCE=true
- shift 1;;
- *) GHC_VER=$1
- break;;
- esac
- done
- if [ -z "${GHC_VER}" ] ; then
- _tool_ver="$(get_tool_ver_from_tag "ghc" "recommended")"
- if [ -z "${_tool_ver}" ] ; then
- die "Could not find a recommended GHC version, please report a bug at ${BUG_URL}!"
- fi
- install_ghc "${_tool_ver}" "${MY_OS}"
- else
- # could be a version or a tag, let's check
- if array_contains "${GHC_VER}" "$(known_tool_versions "ghc")" ; then
- install_ghc "${GHC_VER}" "${MY_OS}"
- elif array_contains "${GHC_VER}" "$(known_tool_tags "ghc")" ; then
- install_ghc "$(get_tool_ver_from_tag "ghc" "${GHC_VER}")" "${MY_OS}"
- else
- die "\"${GHC_VER}\" is not a known version or tag!"
- fi
- fi
- break;;
- set)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) set_usage;;
- *) GHC_VER=$1
- break;;
- esac
- done
-
- if [ -z "${GHC_VER}" ] ; then
- _tool_ver="$(get_tool_ver_from_tag "ghc" "recommended")"
- if [ -z "${_tool_ver}" ] ; then
- die "Could not find a recommended GHC version, please report a bug at ${BUG_URL}!"
- fi
- set_ghc "${_tool_ver}"
- else
- # could be a version or a tag, let's check
- if array_contains "${GHC_VER}" "$(known_tool_versions "ghc")" ; then
- set_ghc "${GHC_VER}"
- elif array_contains "${GHC_VER}" "$(known_tool_tags "ghc")" ; then
- set_ghc "$(get_tool_ver_from_tag "ghc" "${GHC_VER}")"
- else
- die "\"${GHC_VER}\" is not a known version or tag!"
- fi
- fi
-
- break;;
- upgrade)
- IN_PLACE=false
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) upgrade_usage;;
- -i|--inplace) IN_PLACE=true
- shift 1 ;;
- *) TARGET_LOCATION=$1
- break;;
- esac
- done
- if ${IN_PLACE} ; then
- upgrade "$(dirname "$(posix_realpath "${SOURCE}")")"
- elif [ -n "${TARGET_LOCATION}" ] ; then
- upgrade "${TARGET_LOCATION}"
- else
- upgrade "${BIN_LOCATION}"
- fi
- break;;
- rm)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) rm_usage;;
- -f|--force) FORCE=true
- shift 1;;
- *) GHC_VER=$1
- break;;
- esac
- done
- [ -n "${GHC_VER}" ] || rm_usage
- rm_ghc "${GHC_VER}"
- break;;
- install-cabal)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) install_cabal_usage;;
- -f|--force) FORCE=true
- shift 1;;
- *) CABAL_VER=$1
- break;;
- esac
- done
- if [ -n "${CABAL_VER}" ] ; then
- # could be a version or a tag, let's check
- if array_contains "${CABAL_VER}" "$(known_tool_versions "cabal-install")" ; then
- install_cabal "${CABAL_VER}" "${MY_OS}"
- elif array_contains "${CABAL_VER}" "$(known_tool_tags "cabal-install")" ; then
- install_cabal "$(get_tool_ver_from_tag "cabal-install" "${CABAL_VER}")" "${MY_OS}"
- else
- die "\"${CABAL_VER}\" is not a known version or tag!"
- fi
- else
- _cabal_ver="$(get_tool_ver_from_tag "cabal-install" "recommended")"
- if [ -z "${_cabal_ver}" ] ; then
- die "Could not find a recommended cabal-install version, please report a bug at ${BUG_URL}!"
- fi
- install_cabal "${_cabal_ver}" "${MY_OS}"
- fi
- break;;
- compile)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) compile_usage;;
- -f|--force) FORCE=true
- shift 1;;
- -j|--jobs) JOBS=$2
- shift 2;;
- -c|--build-config) BUILD_CONFIG=$2
- shift 2;;
- *) GHC_VER=$1
- BOOTSTRAP_GHC=$2
- break;;
- esac
- done
- [ -n "${GHC_VER}" ] || compile_usage
- [ -n "${BOOTSTRAP_GHC}" ] || compile_usage
- compile_ghc "${GHC_VER}" "${BOOTSTRAP_GHC}" "${BUILD_CONFIG}"
- break;;
- debug-info)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) debug_info_usage;;
- *) debug_info_usage;;
- esac
- done
- print_debug_info
- break;;
- list)
- RAW_FORMAT=false
- TOOL="ghc"
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) list_usage;;
- -t|--tool) TOOL=$2
- shift 2;;
- -r|--raw-format) RAW_FORMAT=true
- shift 1;;
- -c|--show-criteria) SHOW_CRITERIA=$2
- shift 2;;
- *) list_usage;;
- esac
- done
- list "${TOOL}" ${RAW_FORMAT} "${SHOW_CRITERIA}"
- break;;
- changelog)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) changelog_usage;;
- -f|--force) FORCE=true
- shift 1;;
- *) GHC_VER=$1
- break;;
- esac
- done
- if [ -z "${GHC_VER}" ] ; then
- _tool_ver="$(get_tool_ver_from_tag "ghc" "latest")"
- if [ -z "${_tool_ver}" ] ; then
- die "Could not find a latest GHC version, please report a bug at ${BUG_URL}!"
- fi
- changelog "${_tool_ver}"
- else
- # could be a version or a tag, let's check
- if array_contains "${GHC_VER}" "$(known_tool_versions "ghc")" ; then
- changelog "${GHC_VER}"
- elif array_contains "${GHC_VER}" "$(known_tool_tags "ghc")" ; then
- changelog "$(get_tool_ver_from_tag "ghc" "${GHC_VER}")"
- else
- die "\"${GHC_VER}\" is not a known version or tag!"
- fi
- fi
- break;;
- print-system-reqs)
- shift 1
- while [ $# -gt 0 ] ; do
- case $1 in
- -h|--help) print_system_reqs_usage;;
- *) print_system_reqs_usage;;
- esac
- done
- print_system_reqs
- break;;
- *) usage;;
- esac
- break;;
- esac
- done
-
-
- # vim: tabstop=4 shiftwidth=4 expandtab
|