#!/bin/sh ################## https://github.com/mkropat/sh-realpath ##################### # # The MIT License (MIT) # # Copyright (c) 2014 Michael Kropat # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. realpath() { canonicalize_path "$(resolve_symlinks "$1")" } resolve_symlinks() { _resolve_symlinks "$1" } _resolve_symlinks() ( _assert_no_path_cycles "$@" || return if path=$(readlink -- "$1"); then dir_context=$(dirname -- "$1") _resolve_symlinks "$(_prepend_dir_context_if_necessary "$dir_context" "$path")" "$@" else printf '%s\n' "$1" fi ) _prepend_dir_context_if_necessary() { if [ "$1" = . ]; then printf '%s\n' "$2" else _prepend_path_if_relative "$1" "$2" fi } _prepend_path_if_relative() { case "$2" in /* ) printf '%s\n' "$2" ;; * ) printf '%s\n' "$1/$2" ;; esac } _assert_no_path_cycles() ( target=$1 shift for path in "$@"; do if [ "$path" = "$target" ]; then return 1 fi done ) canonicalize_path() { if [ -d "$1" ]; then _canonicalize_dir_path "$1" else _canonicalize_file_path "$1" fi } _canonicalize_dir_path() { { cd "$1" 2>/dev/null && pwd -P; } } _canonicalize_file_path() ( dir=$(dirname -- "$1") file=$(basename -- "$1") { cd "$dir" 2>/dev/null >/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file"; } ) ############################################################################## # Based on http://stackoverflow.com/q/370047/641451 remove_path_item() ( path="$1" printf "%s" "$path" | awk -v item="$2" -v RS=: -v ORS=: '$0 != item' | sed 's/:$//' ) ############################################################################## __has_colors() ( num_colors=$(tput colors 2>/dev/null) if [ -n "$num_colors" ] && [ "$num_colors" -gt 2 ]; then return 0 else return 1 fi ) __error_msg() { if __has_colors; then # bold red coloring printf '%b\n' "\033[31;1m$*\033[0m" 1>&2 else printf '%b\n' "$@" 1>&2 fi } __warning_msg() { if __has_colors; then # brown coloring printf '%b\n' "\033[33m$*\033[0m" 1>&2 else printf '%b\n' "$@" 1>&2 fi } SCRIPT_PATH="$(realpath "$0")" SCRIPT_ROOT="$(dirname "$SCRIPT_PATH")" CRYSTAL_ROOT="$(dirname "$SCRIPT_ROOT")" CRYSTAL_DIR="$CRYSTAL_ROOT/.build" export CRYSTAL_PATH="${CRYSTAL_PATH:-./lib:$CRYSTAL_ROOT/src}" if [ -n "${CRYSTAL_PATH##*"$CRYSTAL_ROOT"/src*}" ]; then __warning_msg "CRYSTAL_PATH env variable does not contain $CRYSTAL_ROOT/src" fi export CRYSTAL_HAS_WRAPPER=true : "${CRYSTAL=crystal}" PARENT_CRYSTAL="$CRYSTAL" # check if the parent crystal command is a path that refers to this script if [ -z "${PARENT_CRYSTAL##*/*}" ] && [ "$(realpath "$PARENT_CRYSTAL")" = "$SCRIPT_PATH" ]; then # ignore it and use `crystal` as parent compiler command PARENT_CRYSTAL="crystal" fi # check if the parent crystal command refers to this script if [ "$(realpath "$(command -v "$PARENT_CRYSTAL" 2> /dev/null)" 2> /dev/null)" = "$SCRIPT_PATH" ]; then # remove the path to this script from PATH NEW_PATH="$(remove_path_item "$(remove_path_item "$PATH" "$SCRIPT_ROOT")" "bin")" # if the PATH did not change it will lead to an infinite recursion => display error if [ "$NEW_PATH" = "$PATH" ]; then __error_msg 'Could not remove the script bin/crystal from the PATH. Remove it by hand or set the CRYSTAL env variable' exit 1 fi PARENT_CRYSTAL=$(PATH=$NEW_PATH command -v "$PARENT_CRYSTAL" 2> /dev/null) if [ "$(realpath "$PARENT_CRYSTAL" 2> /dev/null)" = "$SCRIPT_PATH" ]; then __error_msg 'Could not remove the script bin/crystal from the PATH. Remove it by hand or set the CRYSTAL env variable' exit 1 fi fi command -v "$PARENT_CRYSTAL" > /dev/null 2> /dev/null PARENT_CRYSTAL_EXISTS=$(test !$?) if ($PARENT_CRYSTAL_EXISTS); then if [ -z "$CRYSTAL_CONFIG_LIBRARY_PATH" ] || [ -z "$CRYSTAL_LIBRARY_PATH" ]; then CRYSTAL_INSTALLED_LIBRARY_PATH="$($PARENT_CRYSTAL env CRYSTAL_LIBRARY_PATH 2> /dev/null || echo "")" export CRYSTAL_LIBRARY_PATH="${CRYSTAL_LIBRARY_PATH:-$CRYSTAL_INSTALLED_LIBRARY_PATH}" export CRYSTAL_CONFIG_LIBRARY_PATH="${CRYSTAL_CONFIG_LIBRARY_PATH:-$CRYSTAL_INSTALLED_LIBRARY_PATH}" fi fi # CRYSTAL_PATH has all symlinks resolved. In order to avoid issues with duplicate file # paths when the working directory is a symlink, we cd into the current directory # with symlinks resolved as well (see https://github.com/crystal-lang/crystal/issues/12969). cd "$(realpath "$(pwd)")" || exit case "$(uname -s)" in CYGWIN*|MSYS_NT*|MINGW32_NT*|MINGW64_NT*) CRYSTAL_BIN="crystal.exe" ;; *) CRYSTAL_BIN="crystal" ;; esac # CRYSTAL_EXEC_PATH determines the location of the `crystal` program for external # compiler commands. CRYSTAL_EXEC_PATH="$SCRIPT_ROOT" export CRYSTAL_EXEC_PATH if [ -x "$CRYSTAL_DIR/${CRYSTAL_BIN}" ]; then __warning_msg "Using compiled compiler at ${CRYSTAL_DIR#"$PWD/"}/${CRYSTAL_BIN}" exec "$CRYSTAL_DIR/${CRYSTAL_BIN}" "$@" elif (! $PARENT_CRYSTAL_EXISTS); then __error_msg 'You need to have a crystal executable in your path! or set CRYSTAL env variable' exit 1 else exec "$PARENT_CRYSTAL" "$@" fi