Skip to content

fix: fix env escaping #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 102 additions & 26 deletions bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -34,47 +34,99 @@ trap 'finish_error $LINENO' ERR

logstamp() { printf "[%s]" "$(TZ='America/Chicago' date +'%Y-%m-%d %H:%M:%S')" ; }
topic() { echo "-----> $(logstamp) $*" ; }
info() { echo " $*" ; }
indent() { sed -u 's/^/ /' ; } # it always runs on linux. on darwin is 'sed -l'
info() { echo " $*" ; }
HEROKU_FREETDS_BUILDPACK_DEBUG="${HEROKU_FREETDS_BUILDPACK_DEBUG:-false}"
debug() {
if [ "$HEROKU_FREETDS_BUILDPACK_DEBUG" = "true" ]; then
echo "[DEBUG] $*"
fi
}
debug_topic() {
if [ "$HEROKU_FREETDS_BUILDPACK_DEBUG" = "true" ]; then
echo "[DEBUG] -----> $*"
fi
}

error() { echo " ! $*" ; >&2 exit 1 ; }
indent() {
local command; command='s/^/ /'
case $(uname) in
Darwin) sed -l "$command";;
*) sed -u "$command";;
esac
}

BUILD_DIR="$1"
CACHE_DIR="$2"
mkdir -p "$BUILD_DIR" "$CACHE_DIR"
# shellcheck disable=SC2034
ENV_DIR="${3}"
# echo "$STACK"
# echo "$SOURCE_VERSION"
# See https://devcenter.heroku.com/articles/buildpack-api#bin-compile-summary

mkdir -p "$BUILD_DIR" "$CACHE_DIR"
# Store which STACK we are running on in the cache to bust the cache if it changes
if [ -f "${CACHE_DIR}/.freetds/STACK" ]; then
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new, cache everything in a .freetds directory

CACHED_STACK=$(cat "$CACHE_DIR/.freetds/STACK")
else
CACHED_STACK=$STACK
fi
# Ensure we store the STACK in the cache for next time.
mkdir -p "$CACHE_DIR/.freetds"
echo "$STACK" > "$CACHE_DIR/.freetds/STACK"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new, cache reference to stack.


BIN_DIR="$(cd "$(dirname "$0")"; pwd)" # absolute path
LP_DIR="$(cd "$(dirname "$0")"; cd ..; pwd)"
ROOT_DIR="$(dirname "$BIN_DIR")"

info "BIN_DIR=${BIN_DIR}, ROOT_DIR=${ROOT_DIR}, BUILD_DIR=${BUILD_DIR}, CACHE_DIR=${CACHE_DIR}, pwd=$(pwd)"
info "BIN_DIR=${BIN_DIR}, ROOT_DIR=${ROOT_DIR}, BUILD_DIR=${BUILD_DIR}, CACHE_DIR=${CACHE_DIR}, CACHED_STACK=${CACHED_STACK} pwd=$(pwd)"

debug_exported_env_vars() {
debug "ENV VARS"
debug "ENV VARS: PATH=${PATH:-}"
debug "ENV VARS: FREETDS_DIR=${FREETDS_DIR:-}"
debug "ENV VARS: LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}"
debug "ENV VARS: LD_RUN_PATH=${LD_RUN_PATH:-}"
debug "ENV VARS: LIBRARY_PATH=${LIBRARY_PATH:-}"
debug "ENV VARS: SYBASE=${SYBASE:-}"
}

debug_topic "debug env vars before load_env_vars"
debug_exported_env_vars

load_env_vars() {
local env_var; env_var="${1:-}"
until [ -z "$env_var" ]; do [ -f "$ENV_DIR/$env_var" ] && export "$env_var=$(cat "$ENV_DIR/$env_var")"; shift ; env_var="${1:-}" ; done
}
load_env_vars "FREETDS_VERSION" "FREETDS_ARCHIVE_NAME" "TDS_VERSION" "FREETDS_REBUILD" "USE_GNUTLS"

debug_topic "debug env vars after load_env_vars"
debug_exported_env_vars

FREETDS_VERSION="${FREETDS_VERSION:-1.00.109}"
FREETDS_ARCHIVE_NAME="${FREETDS_ARCHIVE_NAME:-freetds-${FREETDS_VERSION}}"
TDS_VERSION="${TDS_VERSION:-7.3}" # or TDSVER
USE_GNUTLS="${USE_GNUTLS:---with-gnutls}"

CACHED_TAR="${CACHE_DIR}/freetds-${FREETDS_VERSION}-heroku.tar.bz2"
# Default rebuild to true since I'm having issues linking the library to tiny_tds gem with a cached build.
if [ "${FREETDS_REBUILD:-}" = "true" ]; then
FREETDS_CACHE_DIR="$CACHE_DIR/freetds/cache"
mkdir -p "${FREETDS_CACHE_DIR}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new namespaced directory

CACHED_TAR="${FREETDS_CACHE_DIR}/freetds-${FREETDS_VERSION}-heroku.tar.bz2"
if [[ "$CACHED_STACK" != "$STACK" ]] ; then
topic "Stack has changed. Clearing cache"
rm -f "$CACHED_TAR"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🆕

elif [ "${FREETDS_REBUILD:-}" = "true" ]; then
# Default rebuild to true since I'm having issues linking the library to tiny_tds gem with a cached build.
topic "FREETDS_REBUILD is true. Clearing cache"
rm -f "$CACHED_TAR"
fi

# This installation target is in the BUILD_DIR, which means that
# it'll end up in the slug at runtime.
BUILD_TARGET_DIR="${BUILD_DIR}/freetds"
BUILD_TARGET_DIR="${BUILD_DIR}/.freetds"
mkdir -p "${BUILD_TARGET_DIR}"

# This is the path that will be used at dyno runtime, and in which we build.
APP_TARGET_DIR="/app/freetds"
APP_TARGET_DIR="${HOME:-app}/.freetds" # /app/freetds"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new: always home, always in .freetds

mkdir -p "${APP_TARGET_DIR}"

configure_app_env_vars() {
Expand All @@ -84,44 +136,51 @@ configure_app_env_vars() {
# These exports must point to /app, because the profile is
# executed in a running dyno, not the buildpack environment
cat <<EOF > "${BUILD_DIR}/.profile.d/freetds.sh"
export PATH="${APP_TARGET_DIR}/bin:\$PATH"
export PATH="\${HOME}/.freetds/bin:\$PATH"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new, always escape, always use home

# tiny_tds extconf.rb uses FREETDS_DIR
# https://github.com/rails-sqlserver/tiny_tds/blob/5046755ca91594003f8b3ca541d136f3ed859973/ext/tiny_tds/extconf.rb#L36-L38
export FREETDS_DIR="${APP_TARGET_DIR}"
export LD_LIBRARY_PATH="${APP_TARGET_DIR}/lib:${LD_LIBRARY_PATH:-/usr/local/lib}"
export LD_RUN_PATH="${APP_TARGET_DIR}/lib:${LD_RUN_PATH:-/usr/local/lib}"
export LIBRARY_PATH="${APP_TARGET_DIR}/lib:${LIBRARY_PATH:-/usr/local/lib}"
export SYBASE="${APP_TARGET_DIR}"
export FREETDS_DIR="\${HOME}/.freetds"
export LD_LIBRARY_PATH="\${HOME}/.freetds/lib:\${LD_LIBRARY_PATH:-}"
Copy link
Contributor Author

@bf4 bf4 Mar 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new, always escape, no more fallback when empty

export LD_RUN_PATH="\${HOME}/.freetds/lib:\${LD_RUN_PATH:-}"
export LIBRARY_PATH="\${HOME}/.freetds/lib:\${LIBRARY_PATH:-}"
export SYBASE="\${HOME}/.freetds"
EOF
chmod +x "${BUILD_DIR}/.profile.d/freetds.sh"
echo "configured APP env vars:" | indent
indent < "${BUILD_DIR}/.profile.d/freetds.sh"
# shellcheck disable=SC1090
# shellcheck disable=SC1091
. "${BUILD_DIR}/.profile.d/freetds.sh"
}

configure_buildpack_env_vars() {
# These exports point to the build directory, not to /app, so that
# they work for later buildpacks.
export PATH="${BUILD_TARGET_DIR}/bin:$PATH"
export FREETDS_DIR="${BUILD_TARGET_DIR}"
export LD_LIBRARY_PATH="${BUILD_TARGET_DIR}/lib:${LD_LIBRARY_PATH:-/usr/local/lib}"
export LD_RUN_PATH="${BUILD_TARGET_DIR}/lib:${LD_RUN_PATH:-/usr/local/lib}"
export LIBRARY_PATH="${BUILD_TARGET_DIR}/lib:${LIBRARY_PATH:-/usr/local/lib}"
export SYBASE="${APP_TARGET_DIR}"
# Assert $BUILD_TARGET_DIR = $HOME/.freetds # /app/freetds
# Assert $APP_TARGET_DIR = $HOME/.freetds # /app/freetds
export PATH="${HOME}/.freetds/bin:$PATH"
export FREETDS_DIR="${HOME}/.freetds"
export LD_LIBRARY_PATH="${HOME}/.freetds/lib:${LD_LIBRARY_PATH:-}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new, always use home

export LD_RUN_PATH="${HOME}/.freetds/lib:${LD_RUN_PATH:-}"
export LIBRARY_PATH="${HOME}/.freetds/lib:${LIBRARY_PATH:-}"
export SYBASE="${HOME}/.freetds"
# give environment to later buildpacks
export | grep -E -e ' (PATH|LD_LIBRARY_PATH|LIBRARY_PATH|FREETDS_DIR|SYBASE)=' > "${LP_DIR}/export"
export | grep -E -e ' (PATH|LD_LIBRARY_PATH|LD_RUN_PATH|LIBRARY_PATH|FREETDS_DIR|SYBASE)=' > "${LP_DIR}/export"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new, use LD_RUN_PATH


echo "configured BUILDPACK env vars:" | indent
indent < "${LP_DIR}/export"

topic "Rewrite package-config files"
find "$BUILD_DIR/.freetds" -type f -ipath '*/pkgconfig/*.pc' | xargs --no-run-if-empty -n 1 sed -i -e 's!^prefix=\(.*\)$!prefix='"$BUILD_DIR"'/.freetds\1!g'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new from heroku-aptfile-buildpack. not sure if important

}

download_and_extract_freetds_archive() {
FREETDS_FILE="$FREETDS_ARCHIVE_NAME.tar.gz"
FREETDS_URL="https://www.freetds.org/files/stable/${FREETDS_FILE}"
# TODO(BF): Print log when HEROKUR_FREETDS_BUILDPACK_DEBUG is set
# TODO(BF): Consider calculating and verifying SHA256: openssl dgst -sha256 < "$FREETDS_FILE"
curl -s "$FREETDS_URL" | tar xzvf - -C "${BUILD_DIR}" > "${BUILD_DIR}/build_log-unpack.log" # Can't write to the archive dir until it exists
if [ "$HEROKU_FREETDS_BUILDPACK_DEBUG" = "true" ]; then
debug "$(cat "${BUILD_DIR}/build_log-unpack.log")"
fi
mv "${BUILD_DIR}/build_log-unpack.log" "${BUILD_DIR}/${FREETDS_ARCHIVE_NAME}/"
}

Expand Down Expand Up @@ -152,13 +211,20 @@ build_and_install_freetds() {
--disable-debug \
"--with-tdsver=${TDS_VERSION}"
EOF
# TODO(BF): Print log when HEROKUR_FREETDS_BUILDPACK_DEBUG is set
/bin/bash .build_options > build_log-configure.stdout.log 2> build_log-configure.stderr.log
if [ "$HEROKU_FREETDS_BUILDPACK_DEBUG" = "true" ]; then
debug "$(cat .build_options)"
debug "$(cat build_log-configure.stdout.log)"
debug "$(cat build_log-configure.stderr.log)"
fi
# Flush make output to log since a file will be faster than printing to the screen.
# TODO(BF): Print log when HEROKUR_FREETDS_BUILDPACK_DEBUG is set
{
make && make install && make clean
} > build_log-make_install.stdout.log 2> build_log-make_install.stderr.log
if [ "$HEROKU_FREETDS_BUILDPACK_DEBUG" = "true" ]; then
debug "$(cat build_log-make_install.stdout.log)"
debug "$(cat build_log-make_install.stderr.log)"
fi
cp .build_options build_log-* "${APP_TARGET_DIR}/"

cd "$BUILD_DIR"
Expand All @@ -180,7 +246,11 @@ cache_build_artifacts_for_future_deploys() {
main() {
topic "FreeTDS ${FREETDS_VERSION} building in ${BUILD_DIR}"

debug_topic "debug env vars before configure_app_env_vars"
debug_exported_env_vars
configure_app_env_vars
debug_topic "debug env vars after configure_app_env_vars"
debug_exported_env_vars

if [ ! -f "$CACHED_TAR" ]; then
info "Cached files not found - downloading and unpacking..."
Expand All @@ -197,8 +267,14 @@ main() {
info "Unpacking cached files..."
tar xjf "${CACHED_TAR}" -C "${BUILD_TARGET_DIR}" | indent

debug_topic "debug env vars before configure_buildpack_env_vars"
debug_exported_env_vars

configure_buildpack_env_vars

debug_topic "debug env vars after configure_buildpack_env_vars"
debug_exported_env_vars

info "Install of FreeTDS ${FREETDS_VERSION} complete"
}

Expand Down