970 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			970 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/bin/bash
 | 
						|
# Easy hledger installation script for POSIX systems.
 | 
						|
# Uses cabal if installed and stack is not, 
 | 
						|
# or stack, which it will install if needed (or if --force-install-stack is used).
 | 
						|
# Requires bash and some other POSIX tools.
 | 
						|
# This is based on get-stack.sh which is copyright (c) 2015-2017, Stack contributors.
 | 
						|
 | 
						|
#set -e  # causes trouble, https://github.com/simonmichael/hledger/issues/714
 | 
						|
set -o pipefail
 | 
						|
 | 
						|
usage() {
 | 
						|
  cat <<HERE
 | 
						|
hledger-install.sh [-f|--force-install-stack] [-v|--verbose] [-s|--status] [--version] [-h|--help]
 | 
						|
 | 
						|
Installs the current release of hledger and related tools as reliably and 
 | 
						|
quickly as possible on any POSIX system, using cabal (if installed and 
 | 
						|
stack is not) or stack (installing it when needed or if --force-install-stack is used). 
 | 
						|
With --status, just lists the currently installed hledger tools.
 | 
						|
Usage:
 | 
						|
 | 
						|
 curl -sSLO http://hledger.org/hledger-install.sh  # or wget -qO- ...
 | 
						|
 less hledger-install.sh       # security review
 | 
						|
 bash [-x] hledger-install.sh  # to see commands being run, add -x 
 | 
						|
 | 
						|
or if you prefer convenience to security:
 | 
						|
 | 
						|
 curl -sSL http://hledger.org/hledger-install.sh | bash
 | 
						|
 | 
						|
Once hledger is installed, if you keep hledger-install.sh in \$PATH
 | 
						|
(and upgrade it periodically - currently this must be done manually):
 | 
						|
 | 
						|
 hledger install        # upgrades other hledger tools
 | 
						|
 hledger install -- -s  # shows installation status
 | 
						|
 | 
						|
Note this can require significant time (minutes to hours), memory (~2G),
 | 
						|
and disk space (megabytes to a gigabyte) depending on your connection, 
 | 
						|
machine and past installations. You can kill and rerun it without losing progress.
 | 
						|
(But note if you ctrl-C too vigorously, it might leave a
 | 
						|
"hackage-security-lock" directory which you'll need to remove manually,
 | 
						|
cf https://github.com/commercialhaskell/stack/issues/3055).
 | 
						|
 | 
						|
Version $HLEDGER_INSTALL_VERSION, installs hledger $HLEDGER_VERSION
 | 
						|
HERE
 | 
						|
}
 | 
						|
#TODO https://github.com/commercialhaskell/stack/issues/3055 https://github.com/haskell/hackage-security/issues/187 
 | 
						|
#Updating package index Hackage (mirrored at https://s3.amazonaws.com/hackage.fpcomplete.com/) ...
 | 
						|
#   /Users/simon/.stack/indices/Hackage/hackage-security-lock: createDirectory: already exists (File exists)
 | 
						|
 | 
						|
HLEDGER_INSTALL_TOOL=hledger-install.sh
 | 
						|
  # ^ this script's name (can't use $0 when it's piped into bash)
 | 
						|
 | 
						|
HLEDGER_INSTALL_VERSION=20180312
 | 
						|
 | 
						|
RESOLVER=  #"--resolver=nightly"
 | 
						|
  # ^ You can specify a different stackage snapshot here, 
 | 
						|
  # or comment out this line to use your current global resolver, which might 
 | 
						|
  # avoid some unnecessary building. OSX Sierra+ requires at least lts-8.0. 
 | 
						|
  # lts-6 or 7 probably require tweaking the hledger install commands below. 
 | 
						|
 | 
						|
HLEDGER_LIB_VERSION=1.5
 | 
						|
HLEDGER_VERSION=1.5
 | 
						|
HLEDGER_UI_VERSION=1.5
 | 
						|
HLEDGER_WEB_VERSION=1.5.1
 | 
						|
HLEDGER_API_VERSION=1.5
 | 
						|
 | 
						|
HLEDGER_DIFF_VERSION=0.2.0.13
 | 
						|
HLEDGER_IADD_VERSION=1.3.1
 | 
						|
HLEDGER_INTEREST_VERSION=1.5.1
 | 
						|
HLEDGER_IRR_VERSION=0.1.1.13
 | 
						|
 | 
						|
HLEDGER_MAIN_TOOLS="\
 | 
						|
hledger \
 | 
						|
hledger-ui \
 | 
						|
hledger-web \
 | 
						|
hledger-api \
 | 
						|
"
 | 
						|
 | 
						|
HLEDGER_OTHER_TOOLS="\
 | 
						|
hledger-diff \
 | 
						|
hledger-iadd \
 | 
						|
hledger-interest \
 | 
						|
hledger-irr \
 | 
						|
"
 | 
						|
 | 
						|
# start of (most of) get-stack.sh, https://github.com/commercialhaskell/stack/blob/master/etc/scripts/get-stack.sh
 | 
						|
# modified at CHANGED markers
 | 
						|
 | 
						|
HOME_LOCAL_BIN="$HOME/.local/bin"
 | 
						|
USR_LOCAL_BIN="/usr/local/bin"
 | 
						|
QUIET=""
 | 
						|
FORCE_INSTALL_STACK=""
 | 
						|
STACK_TEMP_DIR=
 | 
						|
 | 
						|
# creates a temporary directory, which will be cleaned up automatically
 | 
						|
# when the script finishes
 | 
						|
make_temp_dir() {
 | 
						|
  STACK_TEMP_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t stack)"
 | 
						|
}
 | 
						|
 | 
						|
# cleanup the temporary directory if it's been created.  called automatically
 | 
						|
# when the script exits.
 | 
						|
cleanup_temp_dir() {
 | 
						|
  if [ -n "$STACK_TEMP_DIR" ] ; then
 | 
						|
    rm -rf "$STACK_TEMP_DIR"
 | 
						|
    STACK_TEMP_DIR=
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# print a message to stderr and exit with error code
 | 
						|
die() {
 | 
						|
  echo "$@" >&2
 | 
						|
  exit 1
 | 
						|
}
 | 
						|
 | 
						|
# print a message to stdout unless '-q' passed to script
 | 
						|
info() {
 | 
						|
  if [ -z "$QUIET" ] ; then
 | 
						|
    echo "$@"
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# print a separator for post-install messages
 | 
						|
post_install_separator() {
 | 
						|
  info ""
 | 
						|
  info "-------------------------------------------------------------------------------"
 | 
						|
  info ""
 | 
						|
}
 | 
						|
 | 
						|
# determines the the CPU's instruction set
 | 
						|
get_isa() {
 | 
						|
  if arch | grep -q arm ; then
 | 
						|
    echo arm
 | 
						|
  else
 | 
						|
    echo x86
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# exits with code 0 if arm ISA is detected as described above
 | 
						|
is_arm() {
 | 
						|
  test "$(get_isa)" = arm
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# determines 64- or 32-bit architecture
 | 
						|
# if getconf is available, it will return the arch of the OS, as desired
 | 
						|
# if not, it will use uname to get the arch of the CPU, though the installed
 | 
						|
# OS could be 32-bits on a 64-bit CPU
 | 
						|
get_arch() {
 | 
						|
  if has_getconf ; then
 | 
						|
    if getconf LONG_BIT | grep -q 64 ; then
 | 
						|
      echo 64
 | 
						|
    else
 | 
						|
      echo 32
 | 
						|
    fi
 | 
						|
  else
 | 
						|
    case "$(uname -m)" in
 | 
						|
      *64)
 | 
						|
        echo 64
 | 
						|
        ;;
 | 
						|
      *)
 | 
						|
        echo 32
 | 
						|
        ;;
 | 
						|
    esac
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# exits with code 0 if a 64-bit architecture is detected as described above
 | 
						|
is_64_bit() {
 | 
						|
  test "$(get_arch)" = 64
 | 
						|
}
 | 
						|
 | 
						|
# prints a generic bindist notice
 | 
						|
print_bindist_notice() {
 | 
						|
  if [ -z "$1" ] ; then
 | 
						|
    info ""
 | 
						|
    info "Using generic bindist..."
 | 
						|
    info ""
 | 
						|
  else
 | 
						|
    info ""
 | 
						|
    info "Using generic $1 bindist..."
 | 
						|
    info ""
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Adds a `sudo` prefix if sudo is available to execute the given command
 | 
						|
# If not, the given command is run as is
 | 
						|
sudocmd() {
 | 
						|
  $(command -v sudo) "$@"
 | 
						|
}
 | 
						|
 | 
						|
# Install dependencies for distros that use Apt
 | 
						|
apt_install_dependencies() {
 | 
						|
    info "Installing dependencies..."
 | 
						|
    info ""
 | 
						|
    apt_get_install_pkgs "$@"
 | 
						|
}
 | 
						|
 | 
						|
# Attempts an install on Ubuntu via apt, if possible
 | 
						|
# Expects the version (in Major.Minor format, with any sub-minor removed)
 | 
						|
# as the first and only argument
 | 
						|
# If the version of Ubuntu is unsupported, it attempts to copy the binary
 | 
						|
# and install the necessary dependencies explicitly.
 | 
						|
do_ubuntu_install() {
 | 
						|
 | 
						|
  install_dependencies() {
 | 
						|
    apt_install_dependencies g++ gcc libc6-dev libffi-dev libgmp-dev make xz-utils zlib1g-dev git gnupg  libtinfo-dev
 | 
						|
  }
 | 
						|
 | 
						|
  if is_arm ; then
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_arm_binary
 | 
						|
  elif is_64_bit ; then
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_64bit_static_binary
 | 
						|
  else
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_32bit_standard_binary
 | 
						|
  fi
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
# Attempts an install on Debian.
 | 
						|
# Expects the single-number version as the first and only argument
 | 
						|
# If the version of Debian is unsupported, it attempts to copy the binary
 | 
						|
# and install the necessary dependencies explicitly.
 | 
						|
do_debian_install() {
 | 
						|
 | 
						|
  install_dependencies() {
 | 
						|
    apt_install_dependencies g++ gcc libc6-dev libffi-dev libgmp-dev make xz-utils zlib1g-dev libtinfo-dev
 | 
						|
  }
 | 
						|
 | 
						|
  if is_arm ; then
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_arm_binary
 | 
						|
  elif is_64_bit ; then
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_64bit_static_binary
 | 
						|
  else
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_32bit_standard_binary
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Attempts an install on Fedora.
 | 
						|
# Expects the single-number version as the first and only argument
 | 
						|
# If the version of Fedora is unsupported, it attempts to copy the binary
 | 
						|
# and install the necessary dependencies explicitly.
 | 
						|
do_fedora_install() {
 | 
						|
  install_dependencies() {
 | 
						|
    dnf_install_pkgs perl make automake gcc gmp-devel libffi zlib xz tar
 | 
						|
  }
 | 
						|
 | 
						|
  if is_64_bit ; then
 | 
						|
    install_dependencies "$1"
 | 
						|
    print_bindist_notice
 | 
						|
    install_64bit_static_binary
 | 
						|
  else
 | 
						|
    install_dependencies "$1"
 | 
						|
    print_bindist_notice
 | 
						|
    install_32bit_standard_binary
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Attempts an install on CentOS.
 | 
						|
# Expects the single-number version as the first and only argument
 | 
						|
# If the version of CentOS is unsupported, it attempts to copy the binary
 | 
						|
# and install the necessary dependencies explicitly.
 | 
						|
do_centos_install() {
 | 
						|
  install_dependencies() {
 | 
						|
    yum_install_pkgs perl make automake gcc gmp-devel libffi zlib xz tar
 | 
						|
  }
 | 
						|
 | 
						|
  if is_64_bit ; then
 | 
						|
    install_dependencies
 | 
						|
    print_bindist_notice
 | 
						|
    install_64bit_static_binary
 | 
						|
  else
 | 
						|
    install_dependencies
 | 
						|
    case "$1" in
 | 
						|
      "6")
 | 
						|
        print_bindist_notice "libgmp4"
 | 
						|
        install_32bit_gmp4_linked_binary
 | 
						|
        ;;
 | 
						|
      *)
 | 
						|
        print_bindist_notice
 | 
						|
        install_32bit_standard_binary
 | 
						|
        ;;
 | 
						|
    esac
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Attempts to install on macOS.
 | 
						|
# If 'brew' exists, installs using Homebrew.  Otherwise, installs
 | 
						|
# the generic bindist.
 | 
						|
do_osx_install() {
 | 
						|
  info "Using generic bindist..."
 | 
						|
  info ""
 | 
						|
  install_64bit_osx_binary
 | 
						|
#CHANGED
 | 
						|
#  info "NOTE: You may need to run 'xcode-select --install' to set"
 | 
						|
#  info "      up the Xcode command-line tools, which Stack uses."
 | 
						|
#  info ""
 | 
						|
  echo "NOTE: You may need to run 'xcode-select --install' to set"
 | 
						|
  echo "      up the Xcode command-line tools, which Stack uses."
 | 
						|
  echo ""
 | 
						|
}
 | 
						|
 | 
						|
# Attempts to insall on FreeBSD.  Installs dependencies with
 | 
						|
# 'pkg install' and then downloads bindist.
 | 
						|
do_freebsd_install() {
 | 
						|
  install_dependencies() {
 | 
						|
    pkg_install_pkgs devel/gmake perl5 lang/gcc misc/compat8x misc/compat9x converters/libiconv ca_root_nss
 | 
						|
  }
 | 
						|
  if is_64_bit ; then
 | 
						|
    install_dependencies
 | 
						|
    install_64bit_freebsd_binary
 | 
						|
  else
 | 
						|
    die "Sorry, there is currently no 32-bit FreeBSD binary available."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Alpine distro install
 | 
						|
do_alpine_install() {
 | 
						|
  install_dependencies() {
 | 
						|
    apk_install_pkgs gmp libgcc xz make
 | 
						|
  }
 | 
						|
  install_dependencies
 | 
						|
  if is_64_bit ; then
 | 
						|
    install_64bit_static_binary
 | 
						|
  else
 | 
						|
    die "Sorry, there is currently no 32-bit Alpine Linux binary available."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Attempts to install on unsupported Linux distribution by downloading
 | 
						|
# the bindist.
 | 
						|
do_sloppy_install() {
 | 
						|
  info "This installer doesn't support your Linux distribution, trying generic"
 | 
						|
  info "bindist..."
 | 
						|
  info ""
 | 
						|
 | 
						|
  if is_arm ; then
 | 
						|
      install_arm_binary
 | 
						|
  elif is_64_bit ; then
 | 
						|
      install_64bit_static_binary
 | 
						|
  else
 | 
						|
      install_32bit_standard_binary
 | 
						|
  fi
 | 
						|
  info "Since this installer doesn't support your Linux distribution,"
 | 
						|
  info "there is no guarantee that 'stack' will work at all!  You may"
 | 
						|
  info "need to manually install some system info dependencies for GHC:"
 | 
						|
  info "  gcc, make, libffi, zlib, libgmp and libtinfo"
 | 
						|
  info "Please see http://docs.haskellstack.org/en/stable/install_and_upgrade/"
 | 
						|
  info "Pull requests to add support for this distro would be welcome!"
 | 
						|
  info ""
 | 
						|
}
 | 
						|
 | 
						|
# Attempts to determine the running Linux distribution.
 | 
						|
# Prints "DISTRO;VERSION" (distribution name and version)"."
 | 
						|
distro_info() {
 | 
						|
  parse_lsb() {
 | 
						|
    lsb_release -a 2> /dev/null | perl -ne "$1"
 | 
						|
  }
 | 
						|
 | 
						|
  try_lsb() {
 | 
						|
    if has_lsb_release ; then
 | 
						|
      TL_DIST="$(parse_lsb 'if(/Distributor ID:\s+([^ ]+)/) { print "\L$1"; }')"
 | 
						|
      TL_VERSION="$(parse_lsb 'if(/Release:\s+([^ ]+)/) { print "\L$1"; }')"
 | 
						|
      echo "$TL_DIST;$TL_VERSION"
 | 
						|
    else
 | 
						|
      return 1
 | 
						|
    fi
 | 
						|
  }
 | 
						|
 | 
						|
  try_release() {
 | 
						|
    parse_release() {
 | 
						|
      perl -ne "$1" /etc/*release 2>/dev/null
 | 
						|
    }
 | 
						|
 | 
						|
    parse_release_id() {
 | 
						|
      parse_release 'if(/^(DISTRIB_)?ID\s*=\s*"?([^"]+)/) { print "\L$2"; exit 0; }'
 | 
						|
    }
 | 
						|
 | 
						|
    parse_release_version() {
 | 
						|
      parse_release 'if(/^(DISTRIB_RELEASE|VERSION_ID)\s*=\s*"?([^"]+)/) { print $2; exit 0; }'
 | 
						|
    }
 | 
						|
 | 
						|
    TR_RELEASE="$(parse_release_id);$(parse_release_version)"
 | 
						|
 | 
						|
    if [ ";" = "$TR_RELEASE" ] ; then
 | 
						|
      if [ -e /etc/arch-release ] ; then
 | 
						|
        # /etc/arch-release exists but is often empty
 | 
						|
        echo "arch;"
 | 
						|
      elif [ -e /etc/centos-release ] && grep -q "\\<6\\>" /etc/centos-release ; then
 | 
						|
        # /etc/centos-release has a non-standard format before version 7
 | 
						|
        echo "centos;6"
 | 
						|
      else
 | 
						|
        return 1
 | 
						|
      fi
 | 
						|
    else
 | 
						|
      echo "$TR_RELEASE"
 | 
						|
    fi
 | 
						|
  }
 | 
						|
 | 
						|
  try_issue() {
 | 
						|
    case "$(cat /etc/issue 2>/dev/null)" in
 | 
						|
      "Arch Linux"*)
 | 
						|
        echo "arch;" # n.b. Version is not available in /etc/issue on Arch
 | 
						|
        ;;
 | 
						|
      "Ubuntu"*)
 | 
						|
        echo "ubuntu;$(perl -ne 'if(/Ubuntu (\d+\.\d+)/) { print $1; }' < /etc/issue)"
 | 
						|
        ;;
 | 
						|
      "Debian"*)
 | 
						|
        echo "debian;$(perl -ne 'if(/Debian GNU\/Linux (\d+(\.\d+)?)/) { print $1; }' < /etc/issue)"
 | 
						|
        ;;
 | 
						|
      *"SUSE"*)
 | 
						|
        echo "suse;$(perl -ne 'if(/SUSE\b.* (\d+\.\d+)/) { print $1; }' < /etc/issue)"
 | 
						|
        ;;
 | 
						|
      *"NixOS"*)
 | 
						|
        echo "nixos;$(perl -ne 'if(/NixOS (\d+\.\d+)/) { print $1; }' < /etc/issue)"
 | 
						|
        ;;
 | 
						|
      "CentOS"*)
 | 
						|
        echo "centos;$(perl -ne 'if(/^CentOS release (\d+)\./) { print $1; }' < /etc/issue)"
 | 
						|
        ;;
 | 
						|
      *)
 | 
						|
    esac
 | 
						|
    # others do not output useful info in issue, return empty
 | 
						|
  }
 | 
						|
 | 
						|
  try_lsb || try_release || try_issue
 | 
						|
}
 | 
						|
 | 
						|
# Attempt to install on a Linux distribution
 | 
						|
do_distro() {
 | 
						|
  if ! has_perl ; then
 | 
						|
    if ! try_install_pkgs perl ; then
 | 
						|
      #TODO: remove dependence on 'perl', which is not installed by default
 | 
						|
      #on some distributions (Fedora and RHEL, in particular).
 | 
						|
      die "This script requires 'perl', please install it to continue."
 | 
						|
    fi
 | 
						|
  fi
 | 
						|
 | 
						|
  IFS=";" read -r DISTRO VERSION <<GETDISTRO
 | 
						|
$(distro_info)
 | 
						|
GETDISTRO
 | 
						|
 | 
						|
  if [ -n "$DISTRO" ] ; then
 | 
						|
    info "Detected Linux distribution: $DISTRO"
 | 
						|
    info ""
 | 
						|
  fi
 | 
						|
 | 
						|
  case "$DISTRO" in
 | 
						|
    ubuntu)
 | 
						|
      do_ubuntu_install "$VERSION"
 | 
						|
      ;;
 | 
						|
    debian|kali|raspbian)
 | 
						|
      do_debian_install "$VERSION"
 | 
						|
      ;;
 | 
						|
    fedora)
 | 
						|
      do_fedora_install "$VERSION"
 | 
						|
      ;;
 | 
						|
    centos|rhel)
 | 
						|
      do_centos_install "$VERSION"
 | 
						|
      ;;
 | 
						|
    alpine)
 | 
						|
      do_alpine_install "$VERSION"
 | 
						|
      ;;
 | 
						|
    *)
 | 
						|
      do_sloppy_install
 | 
						|
  esac
 | 
						|
}
 | 
						|
 | 
						|
# Determine operating system and attempt to install.
 | 
						|
do_os() {
 | 
						|
  case "$(uname)" in
 | 
						|
    "Linux")
 | 
						|
      do_distro
 | 
						|
      ;;
 | 
						|
    "Darwin")
 | 
						|
      do_osx_install
 | 
						|
      ;;
 | 
						|
    "FreeBSD")
 | 
						|
      do_freebsd_install
 | 
						|
      ;;
 | 
						|
    *)
 | 
						|
      die "Sorry, this installer does not support your operating system: $(uname).
 | 
						|
See http://docs.haskellstack.org/en/stable/install_and_upgrade/"
 | 
						|
  esac
 | 
						|
}
 | 
						|
 | 
						|
# Download a URL to file using 'curl' or 'wget'.
 | 
						|
dl_to_file() {
 | 
						|
  if has_curl ; then
 | 
						|
    if ! curl ${QUIET:+-sS} -L -o "$2" "$1"; then
 | 
						|
      die "curl download failed: $1"
 | 
						|
    fi
 | 
						|
  elif has_wget ; then
 | 
						|
    if ! wget ${QUIET:+-q} "-O$2" "$1"; then
 | 
						|
      die "wget download failed: $1"
 | 
						|
    fi
 | 
						|
  else
 | 
						|
    # should already have checked for this, otherwise this message will probably
 | 
						|
    # not be displayed, since dl_to_stdout will be part of a pipeline
 | 
						|
    die "Neither wget nor curl is available, please install one to continue."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Check for 'curl' or 'wget' and attempt to install 'curl' if neither found,
 | 
						|
# or fail the script if that is not possible.
 | 
						|
check_dl_tools() {
 | 
						|
  if ! has_curl && ! has_wget ; then
 | 
						|
    if ! try_install_pkgs curl ; then
 | 
						|
      die "Neither wget nor curl is available, please install one to continue."
 | 
						|
    fi
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Download a Stack bindst and install it in /usr/local/bin/stack.
 | 
						|
install_from_bindist() {
 | 
						|
    IFB_URL="https://www.stackage.org/stack/$1"
 | 
						|
    check_dl_tools
 | 
						|
    make_temp_dir
 | 
						|
 | 
						|
    dl_to_file "$IFB_URL" "$STACK_TEMP_DIR/$1.bindist"
 | 
						|
    mkdir -p "$STACK_TEMP_DIR/$1"
 | 
						|
    if ! tar xzf "$STACK_TEMP_DIR/$1.bindist" -C "$STACK_TEMP_DIR/$1"; then
 | 
						|
      die "Extract bindist failed"
 | 
						|
    fi
 | 
						|
#CHANGED
 | 
						|
#    if ! sudocmd install -c -o 0 -g 0 -m 0755 "$STACK_TEMP_DIR/$1"/*/stack "$USR_LOCAL_BIN/stack"; then
 | 
						|
#      die "Install to $USR_LOCAL_BIN/stack failed"
 | 
						|
    ensure_home_local_bin
 | 
						|
    if ! install -m 0755 "$STACK_TEMP_DIR/$1"/*/stack "$HOME_LOCAL_BIN/stack"; then
 | 
						|
      die "Install to $HOME_LOCAL_BIN/stack failed"
 | 
						|
    fi
 | 
						|
 | 
						|
    post_install_separator
 | 
						|
#CHANGED
 | 
						|
#    info "Stack has been installed to: $USR_LOCAL_BIN/stack"
 | 
						|
    echo "Stack has been installed to: $HOME_LOCAL_BIN/stack"
 | 
						|
    info ""
 | 
						|
 | 
						|
#CHANGED
 | 
						|
#    check_usr_local_bin_on_path
 | 
						|
}
 | 
						|
 | 
						|
install_arm_binary() {
 | 
						|
  install_from_bindist "linux-arm"
 | 
						|
}
 | 
						|
 | 
						|
install_32bit_standard_binary() {
 | 
						|
  install_from_bindist "linux-i386"
 | 
						|
}
 | 
						|
 | 
						|
install_64bit_static_binary() {
 | 
						|
  install_from_bindist "linux-x86_64-static"
 | 
						|
}
 | 
						|
 | 
						|
install_32bit_gmp4_linked_binary() {
 | 
						|
  install_from_bindist "linux-i386-gmp4"
 | 
						|
}
 | 
						|
 | 
						|
install_64bit_osx_binary() {
 | 
						|
  install_from_bindist "osx-x86_64"
 | 
						|
}
 | 
						|
 | 
						|
install_64bit_freebsd_binary() {
 | 
						|
  install_from_bindist "freebsd-x86_64"
 | 
						|
}
 | 
						|
 | 
						|
# Attempt to install packages using whichever of apt-get, dnf, yum, or apk is
 | 
						|
# available.
 | 
						|
try_install_pkgs() {
 | 
						|
  if has_apt_get ; then
 | 
						|
    apt_get_install_pkgs "$@"
 | 
						|
  elif has_dnf ; then
 | 
						|
    dnf_install_pkgs "$@"
 | 
						|
  elif has_yum ; then
 | 
						|
    yum_install_pkgs "$@"
 | 
						|
  elif has_apk ; then
 | 
						|
    apk_install_pkgs "$@"
 | 
						|
  else
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Install packages using apt-get
 | 
						|
apt_get_install_pkgs() {
 | 
						|
  if ! sudocmd apt-get install -y ${QUIET:+-qq} "$@"; then
 | 
						|
    die "Installing apt packages failed.  Please run 'apt-get update' and try again."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Install packages using dnf
 | 
						|
dnf_install_pkgs() {
 | 
						|
  if ! sudocmd dnf install -y ${QUIET:+-q} "$@"; then
 | 
						|
    die "Installing dnf packages failed.  Please run 'dnf check-update' and try again."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Install packages using yum
 | 
						|
yum_install_pkgs() {
 | 
						|
  if ! sudocmd yum install -y ${QUIET:+-q} "$@"; then
 | 
						|
    die "Installing yum packages failed.  Please run 'yum check-update' and try again."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Install packages using apk
 | 
						|
apk_install_pkgs() {
 | 
						|
  if ! sudocmd apk add --update ${QUIET:+-q} "$@"; then
 | 
						|
    die "Installing apk packages failed.  Please run 'apk update' and try again."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Install packages using pkg
 | 
						|
pkg_install_pkgs() {
 | 
						|
    if ! sudocmd pkg install -y "$@"; then
 | 
						|
        die "Installing pkg packages failed.  Please run 'pkg update' and try again."
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
# Get installed Stack version, if any
 | 
						|
stack_version() {
 | 
						|
  stack --version | grep -o 'Version \([[:digit:]]\|\.\)\+'
 | 
						|
}
 | 
						|
 | 
						|
# Get installed Stack's path
 | 
						|
stack_location() {
 | 
						|
  command -v stack
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'stack' command exists
 | 
						|
has_stack() {
 | 
						|
  has_cmd stack
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'wget' command exists
 | 
						|
has_wget() {
 | 
						|
  has_cmd wget
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'curl' command exists
 | 
						|
has_curl() {
 | 
						|
  has_cmd curl
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'lsb_release' command exists
 | 
						|
has_lsb_release() {
 | 
						|
  has_cmd lsb_release
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'sudo' command exists
 | 
						|
has_sudo() {
 | 
						|
  has_cmd sudo
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'getconf' command exists
 | 
						|
has_getconf() {
 | 
						|
  has_cmd getconf
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'brew' command exists
 | 
						|
#has_brew() {
 | 
						|
#  has_cmd brew
 | 
						|
#}
 | 
						|
 | 
						|
# Check whether 'perl' command exists
 | 
						|
has_perl() {
 | 
						|
  has_cmd perl
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'apt-get' command exists
 | 
						|
has_apt_get() {
 | 
						|
  has_cmd apt-get
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'yum' command exists
 | 
						|
has_yum() {
 | 
						|
  has_cmd yum
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'apk' command exists
 | 
						|
has_apk() {
 | 
						|
  has_cmd apk
 | 
						|
}
 | 
						|
 | 
						|
# Check whether 'dnf' command exists
 | 
						|
has_dnf() {
 | 
						|
  has_cmd dnf
 | 
						|
}
 | 
						|
 | 
						|
# Check whether the given command exists
 | 
						|
has_cmd() {
 | 
						|
  command -v "$1" > /dev/null 2>&1
 | 
						|
}
 | 
						|
 | 
						|
# Ensure that $HOME/.local/bin/ exists, or die.
 | 
						|
ensure_home_local_bin() {
 | 
						|
  install -d "$HOME_LOCAL_BIN" || die "Creating $HOME_LOCAL_BIN/ directory failed"
 | 
						|
}
 | 
						|
 | 
						|
# Check whether the given path is listed in the PATH environment variable
 | 
						|
on_path() {
 | 
						|
  echo ":$PATH:" | grep -q :"$1":
 | 
						|
}
 | 
						|
 | 
						|
# Check whether ~/.local/bin is on the PATH, and print a warning if not.
 | 
						|
check_home_local_bin_on_path() {
 | 
						|
  if ! on_path "$HOME_LOCAL_BIN" ; then
 | 
						|
    #TODO: offer to add it for the user (pull requests welcome!)
 | 
						|
    info "WARNING: '$HOME_LOCAL_BIN' is not on your PATH."
 | 
						|
    info "    For best results, please add it to the beginning of PATH in your profile."
 | 
						|
    info ""
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Check whether /usr/local/bin is on the PATH, and print a warning if not.
 | 
						|
check_usr_local_bin_on_path() {
 | 
						|
  if ! on_path "$USR_LOCAL_BIN" ; then
 | 
						|
    info "WARNING: '$USR_LOCAL_BIN' is not on your PATH."
 | 
						|
    info ""
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Check whether Stack is already installed, and print an error if it is.
 | 
						|
check_stack_installed() {
 | 
						|
  if [ "$FORCE_INSTALL_STACK" != "true" ] && has_stack ; then
 | 
						|
    die "Stack $(stack_version) already appears to be installed at:
 | 
						|
  $(stack_location)
 | 
						|
Use 'stack upgrade' or your OS's package manager to upgrade,
 | 
						|
or pass --force-install-stack to this script to install anyway."
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
trap cleanup_temp_dir EXIT
 | 
						|
 | 
						|
# end of (most of) get-stack.sh
 | 
						|
 | 
						|
# hledger routines
 | 
						|
 | 
						|
# install stack if needed, or always with --force-install-stack, in $HOME/.local/bin
 | 
						|
ensure_stack() {
 | 
						|
  if ! has_stack || [[ "$FORCE_INSTALL_STACK" == "true" ]] ; then
 | 
						|
    echo "Installing stack"
 | 
						|
    do_os
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# get a sed command that supports EREs
 | 
						|
if sed -r </dev/null >/dev/null 2>&1 ; then
 | 
						|
  SED="sed -r"
 | 
						|
else
 | 
						|
  SED="sed -E"
 | 
						|
fi
 | 
						|
 | 
						|
# Get the given command's location, or empty string if it's not in $PATH.
 | 
						|
cmd_location() {
 | 
						|
  command -v "$1"
 | 
						|
}
 | 
						|
 | 
						|
# Get the given command's version, ie the first number in its --version output, 
 | 
						|
# or empty string if there's a problem.
 | 
						|
cmd_version() {
 | 
						|
  (command "$1" --version 2>/dev/null | grep -E '[0-9]' | $SED -e 's/[^0-9]*([0-9][0-9.]*).*/\1/') || ""
 | 
						|
}
 | 
						|
 | 
						|
# Check whether the given command exists with given version
 | 
						|
has_cmd_version() {
 | 
						|
  [[ $(cmd_version "$1") == "$2" ]] 
 | 
						|
}
 | 
						|
 | 
						|
# Show a command's presence in $PATH, and its version if present.
 | 
						|
print_cmd_version() {
 | 
						|
  if [[ $(cmd_location "$1") ]]; then
 | 
						|
    echo "$1" $(cmd_version "$1") is installed at $(cmd_location "$1")
 | 
						|
  else
 | 
						|
    echo "$1 not found"
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Show the installation status of the $HLEDGER_MAIN_TOOLS and $HLEDGER_OTHER_TOOLS. 
 | 
						|
print_hledger_versions() {
 | 
						|
  for cmd in $HLEDGER_MAIN_TOOLS $HLEDGER_OTHER_TOOLS $HLEDGER_INSTALL_TOOL ; do print_cmd_version "$cmd"; done
 | 
						|
}
 | 
						|
 | 
						|
# Run a command, but first log it with "Trying" prepended.
 | 
						|
try_info() {
 | 
						|
  echo Trying "$@"
 | 
						|
  "$@"
 | 
						|
}
 | 
						|
 | 
						|
# Run a command if possible, suppressing any error output or non-zero exit code.
 | 
						|
quietly_run() {
 | 
						|
  "$@" 2>/dev/null || true
 | 
						|
}
 | 
						|
 | 
						|
# Try to install the executables of the given package(s) to $HOME/.local/bin, 
 | 
						|
# trying several methods, generally from quickest to most reliable, continuing on failure.
 | 
						|
# Current the installation methods are:
 | 
						|
# - if stack is not installed and cabal is, try cabal install
 | 
						|
# - otherwise install stack if needed and try stack install with specific resolver and ghc
 | 
						|
# For the stack method, it's necessary to provide not only the package(s) you want to
 | 
						|
# install but also all dependencies which are not in the specified stackage $RESOLVER.
 | 
						|
try_install() {
 | 
						|
  (cd  # avoid any project-specific stack/cabal config, install at user level
 | 
						|
   (! has_cmd stack && has_cmd cabal && try_info cabal install "$@" --verbose="$CABAL_VERBOSITY" ) ||
 | 
						|
   (ensure_stack && (
 | 
						|
    #(try_info stack install --install-ghc "$@" --verbosity=$STACK_VERBOSITY ) ||        # existing resolver
 | 
						|
    (try_info stack install --install-ghc $RESOLVER "$@" --verbosity="$STACK_VERBOSITY" )  # specific resolver
 | 
						|
    )
 | 
						|
   ) ||
 | 
						|
   echo Failed to install "$@"
 | 
						|
  )
 | 
						|
}
 | 
						|
 | 
						|
# start
 | 
						|
 | 
						|
# process command-line flags
 | 
						|
 | 
						|
HELPFLAG=""
 | 
						|
STATUSFLAG=""
 | 
						|
VERBOSEFLAG=""
 | 
						|
VERSIONFLAG=""
 | 
						|
 | 
						|
while [ $# -gt 0 ]; do
 | 
						|
  case "$1" in
 | 
						|
    -f|--force-install-stack)
 | 
						|
      FORCE_INSTALL_STACK="true"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    -v|--verbose)
 | 
						|
      VERBOSEFLAG="true"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    -s|--status)
 | 
						|
      STATUSFLAG="true"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    --version)
 | 
						|
      VERSIONFLAG="true"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    -h|--help)
 | 
						|
      HELPFLAG="true"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    *)
 | 
						|
      echo "Invalid argument: $1" >&2
 | 
						|
      exit 1
 | 
						|
      ;;
 | 
						|
  esac
 | 
						|
done
 | 
						|
 | 
						|
if [[ $HELPFLAG ]] ; then
 | 
						|
  usage
 | 
						|
  exit 0
 | 
						|
fi
 | 
						|
 | 
						|
if [[ $VERSIONFLAG ]] ; then
 | 
						|
  echo $HLEDGER_INSTALL_TOOL $HLEDGER_INSTALL_VERSION
 | 
						|
  exit 0
 | 
						|
fi
 | 
						|
 | 
						|
if [[ $VERBOSEFLAG ]]; then
 | 
						|
  CABAL_VERBOSITY=1       # 0-3
 | 
						|
  STACK_VERBOSITY=info    # silent, error, warn, info, debug
 | 
						|
else
 | 
						|
  CABAL_VERBOSITY=0
 | 
						|
  STACK_VERBOSITY=error
 | 
						|
  QUIET="true"
 | 
						|
fi
 | 
						|
 | 
						|
echo "hledger-install.sh $HLEDGER_INSTALL_VERSION $(date)"
 | 
						|
 | 
						|
# ensure ~/.local/bin/ in PATH
 | 
						|
if ! on_path "$HOME_LOCAL_BIN" ; then
 | 
						|
  echo "WARNING: this script installs hledger (and perhaps stack) in '$HOME_LOCAL_BIN'"
 | 
						|
  echo "  but this directory is not in your PATH. Adding it temporarily. To run"
 | 
						|
  echo "  these things easily, please add it to PATH in your shell profile."
 | 
						|
  echo "  Eg, bash users: "
 | 
						|
  echo "    echo \"export PATH=\$PATH:~/.local/bin\" >> ~/.bashrc && source ~/.bashrc"
 | 
						|
  export PATH=$HOME_LOCAL_BIN:$PATH
 | 
						|
fi
 | 
						|
 | 
						|
# show system info
 | 
						|
echo "System info:"
 | 
						|
quietly_run uname -rsv
 | 
						|
quietly_run lsb_release -a
 | 
						|
 | 
						|
# show current installed hledger packages
 | 
						|
echo "Install status:"
 | 
						|
print_hledger_versions
 | 
						|
 | 
						|
if [[ $STATUSFLAG ]] ; then
 | 
						|
  exit 0
 | 
						|
fi
 | 
						|
 | 
						|
# if we'll be using cabal, run cabal update once at the start
 | 
						|
(! has_cmd stack && has_cmd cabal && try_info cabal update )
 | 
						|
 | 
						|
# try installing each package that needs installing, in turn
 | 
						|
echo ----------
 | 
						|
if [[ $(cmd_version hledger) < $HLEDGER_VERSION ]]; then
 | 
						|
  echo Installing hledger
 | 
						|
  try_install hledger-$HLEDGER_VERSION hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
if [[ $(cmd_version hledger-ui) < $HLEDGER_UI_VERSION ]]; then 
 | 
						|
  echo Installing hledger-ui
 | 
						|
  try_install hledger-ui-$HLEDGER_UI_VERSION hledger-$HLEDGER_VERSION hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
    # brick-0.19 data-clist-0.1.2.0
 | 
						|
    # ^ when hledger-iadd requires a non-stack brick, use the same version here to avoid rebuilding
 | 
						|
  echo
 | 
						|
fi
 | 
						|
if [[ $(cmd_version hledger-web) < $HLEDGER_WEB_VERSION ]]; then 
 | 
						|
  echo Installing hledger-web
 | 
						|
  try_install hledger-web-$HLEDGER_WEB_VERSION hledger-$HLEDGER_VERSION hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
if [[ $(cmd_version hledger-api) < $HLEDGER_API_VERSION ]]; then 
 | 
						|
  echo Installing hledger-api
 | 
						|
  try_install hledger-api-$HLEDGER_API_VERSION hledger-$HLEDGER_VERSION hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
# Third-party addons. We allow these to use an older version of
 | 
						|
# hledger-lib, in case their bounds have not been updated yet. 
 | 
						|
if [[ $(cmd_version hledger-diff) < $HLEDGER_DIFF_VERSION ]]; then 
 | 
						|
  echo Installing hledger-diff
 | 
						|
  try_install hledger-diff-$HLEDGER_DIFF_VERSION #hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
if [[ $(cmd_version hledger-iadd) < $HLEDGER_IADD_VERSION ]]; then 
 | 
						|
  echo Installing hledger-iadd
 | 
						|
  try_install hledger-iadd-$HLEDGER_IADD_VERSION #hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
if [[ $(cmd_version hledger-interest) < $HLEDGER_INTEREST_VERSION ]]; then 
 | 
						|
  echo Installing hledger-interest
 | 
						|
  try_install hledger-interest-$HLEDGER_INTEREST_VERSION #hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
if [[ $(cmd_version hledger-irr) < $HLEDGER_IRR_VERSION ]]; then 
 | 
						|
  echo Installing hledger-irr
 | 
						|
  try_install hledger-irr-$HLEDGER_IRR_VERSION #hledger-lib-$HLEDGER_LIB_VERSION
 | 
						|
  echo
 | 
						|
fi
 | 
						|
echo ----------
 | 
						|
 | 
						|
# show new installation status
 | 
						|
print_hledger_versions
 | 
						|
 | 
						|
# warn if $HOME/.local/bin isn't in $PATH
 | 
						|
check_home_local_bin_on_path
 | 
						|
 | 
						|
# TODO
 | 
						|
# check/require ghc-8.0.2+/lts-8+ on osx sierra+
 | 
						|
# automate testing
 | 
						|
# install hledger experimental tools
 | 
						|
# help install c libs
 | 
						|
# try installing system packages
 | 
						|
# help with logging & reporting successes/failures
 | 
						|
# detect latest hledger version & resolver ?
 | 
						|
# detect latest installer version, self upgrade ?
 |