1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
#!/usr/bin/env bash
# Mason Client Version 1.0.0
# See below for `set -euo pipefail`
# Print file + line number when not in CLI mode
if [[ "$0" != "$BASH_SOURCE" ]]; then
function mason_error {
local _LINE _FN _FILE
read _LINE _FN _FILE <<< "`caller 1`"
if [ -t 1 ]; then
>&2 echo -e "\033[1m\033[31m$@ in ${_FILE} on line ${_LINE}\033[0m"
else
>&2 echo "$@ in ${_FILE} on line ${_LINE}"
fi
}
else
function mason_error {
if [ -t 1 ]; then
>&2 echo -e "\033[1m\033[31m$@\033[0m"
else
>&2 echo "$@"
fi
}
fi
function mason_info {
if [ -t 1 ]; then
>&2 echo -e "\033[1m\033[36m$@\033[0m"
else
>&2 echo "$@"
fi
}
function mason_detect_platform {
# Determine platform
if [[ -z "${MASON_PLATFORM:-}" ]]; then
if [[ "`uname -s`" = 'Darwin' ]]; then
MASON_PLATFORM="osx"
else
MASON_PLATFORM="linux"
fi
fi
# Determine platform version string
if [[ -z "${MASON_PLATFORM_VERSION:-}" ]]; then
MASON_PLATFORM_VERSION="`uname -m`"
fi
}
function mason_trim {
local _TMP="${1#"${1%%[![:space:]]*}"}"
echo -n "${_TMP%"${_TMP##*[![:space:]]}"}"
}
function mason_uppercase {
echo -n "$1" | tr "[a-z]" "[A-Z]"
}
function mason_use {
local _HEADER_ONLY=false _PACKAGE _SAFE_PACKAGE _VERSION _PLATFORM_ID _SLUG _INSTALL_PATH _INSTALL_PATH_RELATIVE
while [[ $# -gt 0 ]]; do
if [[ $1 == "--header-only" ]]; then
_HEADER_ONLY=true
elif [[ -z "${_PACKAGE:-}" ]]; then
_PACKAGE="$1"
elif [[ -z "${_VERSION:-}" ]]; then
_VERSION="$1"
else
mason_error "[Mason] mason_use() called with unrecognized arguments: '$@'"
exit 1
fi
shift
done
if [[ -z "${_PACKAGE:-}" ]]; then
mason_error "[Mason] No package name given"
exit 1
fi
# Create a package name that we can use as shell variable names.
_SAFE_PACKAGE="${_PACKAGE//[![:alnum:]]/_}"
if [[ -z "${_VERSION:-}" ]]; then
mason_error "[Mason] Specifying a version is required"
exit 1
fi
_PLATFORM_ID="${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}"
if [[ "${_HEADER_ONLY}" = true ]] ; then
_PLATFORM_ID="headers"
fi
_SLUG="${_PLATFORM_ID}/${_PACKAGE}/${_VERSION}"
_INSTALL_PATH="${MASON_PACKAGE_DIR}/${_SLUG}"
_INSTALL_PATH_RELATIVE="${_INSTALL_PATH#`pwd`/}"
if [[ ! -d "${_INSTALL_PATH}" ]]; then
local _CACHE_PATH _URL _CACHE_DIR _ERROR
_CACHE_PATH="${MASON_PACKAGE_DIR}/.binaries/${_SLUG}.tar.gz"
if [ ! -f "${_CACHE_PATH}" ]; then
# Download the package
_URL="${MASON_REPOSITORY}/${_SLUG}.tar.gz"
mason_info "[Mason] Downloading package ${_URL}..."
_CACHE_DIR="`dirname "${_CACHE_PATH}"`"
mkdir -p "${_CACHE_DIR}"
if ! _ERROR=$(curl --retry 3 --silent --fail --show-error --location "${_URL}" --output "${_CACHE_PATH}.tmp" 2>&1); then
mason_error "[Mason] ${_ERROR}"
exit 1
else
# We downloaded to a temporary file to prevent half-finished downloads
mv "${_CACHE_PATH}.tmp" "${_CACHE_PATH}"
fi
fi
# Unpack the package
mason_info "[Mason] Unpacking package to ${_INSTALL_PATH_RELATIVE}..."
mkdir -p "${_INSTALL_PATH}"
tar xzf "${_CACHE_PATH}" -C "${_INSTALL_PATH}"
fi
# Error out if there is no config file.
if [[ ! -f "${_INSTALL_PATH}/mason.ini" ]]; then
mason_error "[Mason] Could not find mason.ini for package ${_PACKAGE} ${_VERSION}"
exit 1
fi
# We use this instead of declare, since it declare makes local variables when run in a function.
read "MASON_PACKAGE_${_SAFE_PACKAGE}_PREFIX" <<< "${_INSTALL_PATH}"
# Load the configuration from the ini file
local _LINE _KEY _VALUE
while read _LINE; do
_KEY="`mason_trim "${_LINE%%=*}"`"
if [[ "${_KEY}" =~ ^[a-z_]+$ ]]; then
_KEY="`mason_uppercase "${_KEY}"`" # Convert to uppercase
_LINE="${_LINE%%;*}" # Trim trailing comments
_VALUE="`mason_trim "${_LINE#*=}"`"
_VALUE="${_VALUE//\{prefix\}/${_INSTALL_PATH}}" # Replace {prefix}
read "MASON_PACKAGE_${_SAFE_PACKAGE}_${_KEY}" <<< "${_VALUE}"
fi
done < "${_INSTALL_PATH}/mason.ini"
# We're using the fact that this variable is declared to pass back the package name we parsed
# from the argument string to avoid polluting the global namespace.
if [ ! -z ${_MASON_SAFE_PACKAGE_NAME+x} ]; then
_MASON_SAFE_PACKAGE_NAME="${_SAFE_PACKAGE}"
fi
}
function mason_cli {
local _MASON_SAFE_PACKAGE_NAME= _PROP _VAR
if [[ $# -lt 1 ]]; then
mason_error "[Mason] Usage: $0 <property> [--header-only] <name> <version>"
mason_error "[Mason] <property> is one of 'include_dirs', 'definitions', 'options', 'ldflags', 'static_libs', or any custom variables in the package's mason.ini."
exit 1
fi
# Store first argument and pass the remaining arguments to mason_use
_PROP="`mason_uppercase "$1"`"
shift
mason_use "$@"
# Optionally print variables
_VAR="MASON_PACKAGE_${_MASON_SAFE_PACKAGE_NAME}_${_PROP}"
if [[ ! -z "${!_VAR:-}" ]]; then
echo "${!_VAR}"
fi
}
# Directory where Mason packages are located; typically ends with mason_packages
if [[ -z "${MASON_PACKAGE_DIR:-}" ]]; then
MASON_PACKAGE_DIR="`pwd`/mason_packages"
fi
# URL prefix of where packages are located.
if [[ -z "${MASON_REPOSITORY:-}" ]]; then
MASON_REPOSITORY="https://mason-binaries.s3.amazonaws.com"
fi
mason_detect_platform
# Print variables if this shell script is invoked directly.
if [[ "$0" = "$BASH_SOURCE" ]]; then
set -euo pipefail
mason_cli "$@"
fi
|