├── .github └── CODEOWNERS ├── .travis.yml ├── LICENSE ├── README.md ├── bin ├── get_haskell_stack ├── install └── list-all └── renovate.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @asdf-community/asdf-haskell 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | 3 | matrix: 4 | include: 5 | - os: linux 6 | services: 7 | - docker 8 | script: 9 | - | 10 | bash -c "while true; do echo \$(date) - travis building ...; sleep 540; done" & 11 | export PING_LOOP_PID=$! 12 | - | 13 | cat <<-EOF | docker run -i ubuntu bash - 14 | set -e 15 | export DEBIAN_FRONTEND=noninteractive 16 | export CABALFLAGS=--ghc-option=-O0 17 | apt-get update -qq && apt-get install -qq git curl build-essential 18 | git clone https://github.com/asdf-vm/asdf.git 19 | . asdf/asdf.sh 20 | asdf plugin-test haskell https://github.com/vic/asdf-haskell.git 'ghc --help' 21 | EOF 22 | after_script: 23 | - kill -9 $PING_LOOP_PID 24 | 25 | - os: osx 26 | env: 27 | - "CABALFLAGS=--ghc-option=-O0" 28 | before_script: 29 | - git clone https://github.com/asdf-vm/asdf.git 30 | - . asdf/asdf.sh 31 | script: 32 | - | 33 | bash -c "while true; do echo \$(date) - travis building ...; sleep 540; done" & 34 | export PING_LOOP_PID=$! 35 | - asdf plugin-test haskell https://github.com/vic/asdf-haskell.git 'ghc --help' 36 | after_script: 37 | - kill -9 $PING_LOOP_PID 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016, Stack contributors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of stack nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL STACK CONTRIBUTORS BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # asdf-haskell 2 | [![help maintain this lib](https://img.shields.io/badge/looking%20for%20maintainer-DM%20%40vborja-663399.svg)](https://twitter.com/vborja) 3 | 4 | 5 | [Haskell](https://www.haskell.org) plugin for [asdf](https://github.com/asdf-vm/asdf) version manager 6 | 7 | 8 | ## Install 9 | 10 | ```shell 11 | asdf plugin-add haskell https://github.com/vic/asdf-haskell.git 12 | ``` 13 | 14 | ## Use 15 | 16 | This plugin will create a local [Stack](https://haskellstack.org) installation 17 | (inside asdf-haskell `stack/` directory) to manage GHC versions. So you dont need to have already installed stack. 18 | 19 | After installation, `stack`, `ghc`, `ghci`, and `runhaskell` will be available on your path. 20 | 21 | ```shell 22 | # If you need to install a package that produces binaries 23 | stack install cabal-install 24 | 25 | # Be sure to execute reshim afterwards to get them in your path 26 | asdf reshim haskell 27 | ``` 28 | 29 | Check [asdf](https://github.com/asdf-vm/asdf) readme for instructions on how to install & manage versions of Haskell. 30 | 31 | -------------------------------------------------------------------------------- /bin/get_haskell_stack: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # Stack installation script. 4 | # 5 | # This script is meant for quick & easy install via: 6 | # 'curl -sSL https://get.haskellstack.org/ | sh' 7 | # or: 8 | # 'wget -qO- https://get.haskellstack.org/ | sh' 9 | # 10 | # Make pull requests at: 11 | # https://github.com/commercialhaskell/stack/blob/master/etc/scripts/get-stack.sh 12 | # 13 | ### 14 | # 15 | # Adapter for ASDF from 16 | # https://github.com/commercialhaskell/stack/blob/7f6619b7cce69d849cdc2191a66d49a2fd4691c8/etc/scripts/get-stack.sh 17 | ### 18 | 19 | function get_haskell_stack() { 20 | 21 | HOME_LOCAL_BIN="$1" 22 | USR_LOCAL_BIN="$2" 23 | QUIET="" 24 | STACK_TEMP_DIR= 25 | 26 | # creates a temporary directory, which will be cleaned up automatically 27 | # when the script finishes 28 | make_temp_dir() { 29 | STACK_TEMP_DIR="$(mktemp -d)" 30 | } 31 | 32 | # cleanup the temporary directory if it's been created. called automatically 33 | # when the script exits. 34 | cleanup_temp_dir() { 35 | if [ -n "$STACK_TEMP_DIR" ] ; then 36 | rm -rf "$STACK_TEMP_DIR" 37 | STACK_TEMP_DIR= 38 | fi 39 | } 40 | 41 | # print a message to stderr and exit with error code 42 | die() { 43 | echo "$@" >&2 44 | exit 1 45 | } 46 | 47 | # print a message to stdout unless '-q' passed to script 48 | info() { 49 | if [ -z "$QUIET" ] ; then 50 | echo "$@" 51 | fi 52 | } 53 | 54 | # print a separator for post-install messages 55 | post_install_separator() { 56 | info "" 57 | info "-------------------------------------------------------------------------------" 58 | info "" 59 | } 60 | 61 | # determines the the CPU's instruction set 62 | get_isa() { 63 | if uname -m | grep -q arm ; then 64 | echo arm 65 | else 66 | echo x86 67 | fi 68 | } 69 | 70 | # exits with code 0 if arm ISA is detected as described above 71 | is_arm() { 72 | test "$(get_isa)" = arm 73 | } 74 | 75 | 76 | # determines 64- or 32-bit architecture 77 | # if getconf is available, it will return the arch of the OS, as desired 78 | # if not, it will use uname to get the arch of the CPU, though the installed 79 | # OS could be 32-bits on a 64-bit CPU 80 | get_arch() { 81 | if has_getconf ; then 82 | if getconf LONG_BIT | grep -q 64 ; then 83 | echo 64 84 | else 85 | echo 32 86 | fi 87 | else 88 | case "$(uname -m)" in 89 | *64) 90 | echo 64 91 | ;; 92 | *) 93 | echo 32 94 | ;; 95 | esac 96 | fi 97 | } 98 | 99 | # exits with code 0 if a 64-bit architecture is detected as described above 100 | is_64_bit() { 101 | test "$(get_arch)" = 64 102 | } 103 | 104 | # prints a generic bindist notice 105 | print_bindist_notice() { 106 | if [ -z "$1" ] ; then 107 | info "" 108 | info "Using generic bindist..." 109 | info "" 110 | else 111 | info "" 112 | info "Using generic $1 bindist..." 113 | info "" 114 | fi 115 | } 116 | 117 | # Adds a `sudo` prefix if sudo is available to execute the given command 118 | # If not, the given command is run as is 119 | sudocmd() { 120 | $(command -v sudo) "$@" 121 | } 122 | 123 | # Install dependencies for distros that use Apt 124 | apt_install_dependencies() { 125 | info "Installing dependencies..." 126 | info "" 127 | apt_get_install_pkgs "$@" 128 | } 129 | 130 | # Attempts an install on Ubuntu via apt, if possible 131 | # Expects the version (in Major.Minor format, with any sub-minor removed) 132 | # as the first and only argument 133 | # If the version of Ubuntu is unsupported, it attempts to copy the binary 134 | # and install the necessary dependencies explicitly. 135 | do_ubuntu_install() { 136 | 137 | install_dependencies() { 138 | apt_install_dependencies g++ gcc libc6-dev libffi-dev libgmp-dev make xz-utils zlib1g-dev git gnupg 139 | } 140 | 141 | if is_64_bit ; then 142 | install_dependencies 143 | print_bindist_notice 144 | install_64bit_standard_binary 145 | else 146 | install_dependencies 147 | print_bindist_notice 148 | install_32bit_standard_binary 149 | fi 150 | 151 | } 152 | 153 | # Attempts an install on Debian. 154 | # Expects the single-number version as the first and only argument 155 | # If the version of Debian is unsupported, it attempts to copy the binary 156 | # and install the necessary dependencies explicitly. 157 | do_debian_install() { 158 | 159 | install_dependencies() { 160 | apt_install_dependencies g++ gcc libc6-dev libffi-dev libgmp-dev make xz-utils zlib1g-dev 161 | } 162 | 163 | if is_arm ; then 164 | install_dependencies 165 | print_bindist_notice 166 | install_arm_binary 167 | elif is_64_bit ; then 168 | install_dependencies 169 | print_bindist_notice 170 | install_64bit_standard_binary 171 | else 172 | install_dependencies 173 | print_bindist_notice 174 | install_32bit_standard_binary 175 | fi 176 | } 177 | 178 | # Attempts an install on Fedora. 179 | # Expects the single-number version as the first and only argument 180 | # If the version of Fedora is unsupported, it attempts to copy the binary 181 | # and install the necessary dependencies explicitly. 182 | do_fedora_install() { 183 | install_dependencies() { 184 | dnf_install_pkgs perl make automake gcc gmp-devel libffi zlib xz tar 185 | } 186 | 187 | if is_64_bit ; then 188 | install_dependencies "$1" 189 | print_bindist_notice 190 | install_64bit_standard_binary 191 | else 192 | install_dependencies "$1" 193 | print_bindist_notice 194 | install_32bit_standard_binary 195 | fi 196 | } 197 | 198 | # Attempts an install on CentOS. 199 | # Expects the single-number version as the first and only argument 200 | # If the version of CentOS is unsupported, it attempts to copy the binary 201 | # and install the necessary dependencies explicitly. 202 | do_centos_install() { 203 | install_dependencies() { 204 | yum_install_pkgs perl make automake gcc gmp-devel libffi zlib xz tar 205 | } 206 | 207 | if is_64_bit ; then 208 | install_dependencies 209 | print_bindist_notice 210 | install_64bit_standard_binary 211 | else 212 | install_dependencies 213 | case "$1" in 214 | "6") 215 | print_bindist_notice "libgmp4" 216 | install_32bit_gmp4_linked_binary 217 | ;; 218 | *) 219 | print_bindist_notice 220 | install_32bit_standard_binary 221 | ;; 222 | esac 223 | fi 224 | } 225 | 226 | # Attempts to install on macOS. 227 | # If 'brew' exists, installs using Homebrew. Otherwise, installs 228 | # the generic bindist. 229 | do_osx_install() { 230 | info "Using generic bindist..." 231 | info "" 232 | install_64bit_osx_binary 233 | info "NOTE: You may need to run 'xcode-select --install' to set" 234 | info " up the Xcode command-line tools, which Stack uses." 235 | info "" 236 | } 237 | 238 | # Attempts to insall on FreeBSD. Installs dependencies with 239 | # 'pkg install' and then downloads bindist. 240 | do_freebsd_install() { 241 | install_dependencies() { 242 | sudocmd pkg install -y devel/gmake perl5 lang/gcc misc/compat8x misc/compat9x converters/libiconv ca_root_nss 243 | } 244 | if is_64_bit ; then 245 | install_dependencies 246 | install_64bit_freebsd_binary 247 | else 248 | die "Sorry, there is currently no 32-bit FreeBSD binary available." 249 | fi 250 | } 251 | 252 | # Alpine distro install 253 | do_alpine_install() { 254 | install_dependencies() { 255 | apk_install_pkgs gmp libgcc xz make 256 | } 257 | install_dependencies 258 | if is_64_bit ; then 259 | install_64bit_standard_binary 260 | else 261 | die "Sorry, there is currently no 32-bit Alpine Linux binary available." 262 | fi 263 | } 264 | 265 | # Attempts to install on unsupported Linux distribution by downloading 266 | # the bindist. 267 | do_sloppy_install() { 268 | info "This installer doesn't support your Linux distribution, trying generic" 269 | info "bindist..." 270 | info "" 271 | 272 | if is_arm ; then 273 | install_arm_binary 274 | elif is_64_bit ; then 275 | install_64bit_standard_binary 276 | else 277 | install_32bit_standard_binary 278 | fi 279 | info "Since this installer doesn't support your Linux distribution," 280 | info "there is no guarantee that 'stack' will work at all! You may" 281 | info "need to manually install some system info dependencies for GHC:" 282 | info " gcc, make, libffi, zlib, libgmp and libtinfo" 283 | info "Please see http://docs.haskellstack.org/en/stable/install_and_upgrade/" 284 | info "Pull requests to add support for this distro would be welcome!" 285 | info "" 286 | } 287 | 288 | # Attempts to determine the running Linux distribution. 289 | # Prints "DISTRO;VERSION" (distribution name and version)"." 290 | distro_info() { 291 | parse_lsb() { 292 | lsb_release -a 2> /dev/null | perl -ne "$1" 293 | } 294 | 295 | try_lsb() { 296 | if has_lsb_release ; then 297 | TL_DIST="$(parse_lsb 'if(/Distributor ID:\s+([^ ]+)/) { print "\L$1"; }')" 298 | TL_VERSION="$(parse_lsb 'if(/Release:\s+([^ ]+)/) { print "\L$1"; }')" 299 | echo "$TL_DIST;$TL_VERSION" 300 | else 301 | return 1 302 | fi 303 | } 304 | 305 | try_release() { 306 | parse_release() { 307 | perl -ne "$1" /etc/*release 2>/dev/null 308 | } 309 | 310 | parse_release_id() { 311 | parse_release 'if(/^(DISTRIB_)?ID\s*=\s*"?([^"]+)/) { print "\L$2"; exit 0; }' 312 | } 313 | 314 | parse_release_version() { 315 | parse_release 'if(/^(DISTRIB_RELEASE|VERSION_ID)\s*=\s*"?([^"]+)/) { print $2; exit 0; }' 316 | } 317 | 318 | TR_RELEASE="$(parse_release_id);$(parse_release_version)" 319 | 320 | if [ ";" = "$TR_RELEASE" ] ; then 321 | if [ -e /etc/arch-release ] ; then 322 | # /etc/arch-release exists but is often empty 323 | echo "arch;" 324 | elif [ -e /etc/centos-release ] && grep -q "\<6\>" /etc/centos-release ; then 325 | # /etc/centos-release has a non-standard format before version 7 326 | echo "centos;6" 327 | else 328 | return 1 329 | fi 330 | else 331 | echo "$TR_RELEASE" 332 | fi 333 | } 334 | 335 | try_issue() { 336 | case "$(cat /etc/issue 2>/dev/null)" in 337 | "Arch Linux"*) 338 | echo "arch;" # n.b. Version is not available in /etc/issue on Arch 339 | ;; 340 | "Ubuntu"*) 341 | echo "ubuntu;$(perl -ne 'if(/Ubuntu (\d+\.\d+)/) { print $1; }' < /etc/issue)" 342 | ;; 343 | "Debian"*) 344 | echo "debian;$(perl -ne 'if(/Debian GNU\/Linux (\d+(\.\d+)?)/) { print $1; }' < /etc/issue)" 345 | ;; 346 | *"SUSE"*) 347 | echo "suse;$(perl -ne 'if(/SUSE\b.* (\d+\.\d+)/) { print $1; }' < /etc/issue)" 348 | ;; 349 | *"NixOS"*) 350 | echo "nixos;$(perl -ne 'if(/NixOS (\d+\.\d+)/) { print $1; }' < /etc/issue)" 351 | ;; 352 | "CentOS"*) 353 | echo "centos;$(perl -ne 'if(/^CentOS release (\d+)\./) { print $1; }' < /etc/issue)" 354 | ;; 355 | *) 356 | esac 357 | # others do not output useful info in issue, return empty 358 | } 359 | 360 | try_lsb || try_release || try_issue 361 | } 362 | 363 | # Attempt to install on a Linux distribution 364 | do_distro() { 365 | if ! has_perl ; then 366 | if ! try_install_pkgs perl ; then 367 | #TODO: remove dependence on 'perl', which is not installed by default 368 | #on some distributions (Fedora and RHEL, in particular). 369 | die "This script requires 'perl', please install it to continue." 370 | fi 371 | fi 372 | 373 | IFS=";" read -r DISTRO VERSION < /dev/null 2>&1 600 | } 601 | 602 | # Check whether the given path is listed in the PATH environment variable 603 | on_path() { 604 | echo ":$PATH:" | grep -q :"$1": 605 | } 606 | 607 | # Check whether ~/.local/bin is on the PATH, and print a warning if not. 608 | check_home_local_bin_on_path() { 609 | if ! on_path "$HOME_LOCAL_BIN" ; then 610 | #TODO: offer to add it for the user (pull requests welcome!) 611 | info "WARNING: '$HOME_LOCAL_BIN' is not on your PATH." 612 | info " For best results, please add it to the beginning of PATH in your profile." 613 | info "" 614 | fi 615 | } 616 | 617 | # Check whether /usr/local/bin is on the PATH, and print a warning if not. 618 | check_usr_local_bin_on_path() { 619 | if ! on_path "$USR_LOCAL_BIN" ; then 620 | info "WARNING: '$USR_LOCAL_BIN' is not on your PATH." 621 | info "" 622 | fi 623 | } 624 | 625 | # Check whether Stack is already installed, and print an error if it is. 626 | check_stack_installed() { 627 | if has_stack ; then 628 | #XXX add a --force flag to reinstall anyway 629 | die "Stack $(stack_version) already appears to be installed at: 630 | $(stack_location) 631 | Use 'stack upgrade' or your OS's package manager to upgrade." 632 | fi 633 | } 634 | 635 | trap cleanup_temp_dir EXIT 636 | 637 | case "$1" in 638 | -q|--quiet) 639 | # This tries its best to reduce output by suppressing the script's own 640 | # messages and passing "quiet" arguments to tools that support them. 641 | QUIET="true" 642 | esac 643 | 644 | check_stack_installed 645 | do_os 646 | check_home_local_bin_on_path 647 | 648 | } 649 | -------------------------------------------------------------------------------- /bin/install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ghc_version () { 4 | local version=$1 5 | local url="https://downloads.haskell.org/~ghc/${version}/" 6 | curl --compressed -s "$url" | grep -oE 'ghc-[^-]+' | head -n 1 | sed -e 's/ghc-//g' 7 | } 8 | 9 | ghc_install() { 10 | local install_type=$1 11 | local release=$2 12 | local version=$(ghc_version $release) 13 | local install_path=$3 14 | 15 | local tmp_dir=$(mktemp -d -t haskell_XXXXXXX) 16 | 17 | local current_script_path=$(dirname ${BASH_SOURCE[0]}) 18 | local plugin_path=$(dirname $current_script_path) 19 | local stack_path=$plugin_path/stack 20 | export PATH=$stack_path:$PATH 21 | 22 | if [ "$install_type" != "version" ]; then 23 | echo "asdf-haskell supports release installs only." 24 | exit 1 25 | fi 26 | 27 | if [ ! -x $stack_path/stack ]; then 28 | source $plugin_path/bin/get_haskell_stack 29 | mkdir -p $stack_path 30 | get_haskell_stack $stack_path $stack_path >/dev/null 31 | fi 32 | 33 | 34 | # running this in a subshell 35 | # we don't want to disturb current working dir 36 | ( 37 | set -e 38 | cd $tmp_dir 39 | 40 | local local_bin=$install_path/bin 41 | local stack_root=$install_path/stack 42 | 43 | mkdir -p $stack_root 44 | mkdir -p $local_bin 45 | 46 | echo "Installing Haskell $release (ghc-$version)" 47 | echo "STACK_ROOT=$stack_root" 48 | 49 | cat < $local_bin/stack 50 | #!/usr/bin/env bash 51 | exec $stack_path/stack --stack-root "$stack_root" --local-bin-path "$local_bin" --compiler "ghc-$version" \$* 52 | EOF 53 | 54 | cat < $local_bin/ghc 55 | #!/usr/bin/env bash 56 | exec $local_bin/stack exec ghc -- \$* 57 | EOF 58 | 59 | cat < $local_bin/ghci 60 | #!/usr/bin/env bash 61 | exec $local_bin/stack exec ghci -- \$* 62 | EOF 63 | 64 | cat < $local_bin/ghc-pkg 65 | #!/usr/bin/env bash 66 | exec $local_bin/stack exec ghc-pkg -- \$* 67 | EOF 68 | 69 | cat < $local_bin/haddock 70 | #!/usr/bin/env bash 71 | exec $local_bin/stack exec haddock -- \$* 72 | EOF 73 | 74 | cat < $local_bin/runghc 75 | #!/usr/bin/env bash 76 | exec $local_bin/stack exec runghc -- \$* 77 | EOF 78 | 79 | cat < $local_bin/runhaskell 80 | #!/usr/bin/env bash 81 | exec $local_bin/stack exec runhaskell -- \$* 82 | EOF 83 | 84 | chmod +x $local_bin/* 85 | 86 | $local_bin/stack --install-ghc setup 87 | 88 | ) || (rm -rf $install_path; exit 1) 89 | } 90 | 91 | ghc_install $ASDF_INSTALL_TYPE $ASDF_INSTALL_VERSION $ASDF_INSTALL_PATH 92 | -------------------------------------------------------------------------------- /bin/list-all: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ghc_releases=https://downloads.haskell.org/~ghc/ 4 | 5 | # stolen from https://github.com/rbenv/ruby-build/pull/631/files#diff-fdcfb8a18714b33b07529b7d02b54f1dR942 6 | function sort_versions() { 7 | sed 'h; s/[+-]/./g; s/.p\([[:digit:]]\)/.z\1/; s/$/.z/; G; s/\n/ /' | \ 8 | LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}' 9 | } 10 | 11 | function ghc_versions () { 12 | curl --compressed -s "$ghc_releases" | grep -oE '[0-9]+\.[^/]+' | uniq 13 | } 14 | 15 | versions="$(ghc_versions | sort_versions)" 16 | 17 | echo $versions 18 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | --------------------------------------------------------------------------------