-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathcompile
executable file
·257 lines (221 loc) · 9.15 KB
/
compile
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#!/bin/bash
#
# Usage:
# bin/compile BUILD_DIR CACHE_DIR ENV_DIR
# Example
# BUILD_DIR is /tmp/build_5b72bfcaef1adfe4bb7a9e34d80201fc
# CACHE_DIR is app
# The contents of CACHE_DIR will be persisted between builds.
set -eou pipefail
IFS=$'\n\t'
unset CDPATH
# Always log finish, bash pseudo-signal: EXIT
# Usage:
# trap finish EXIT
finish() {
echo " END Running script: ${0##*/}"
}
# Log errors, if any, bash pseudo-signal: ERR
# Usage:
# trap 'finish_error $LINENO' ERR
finish_error() {
errcode=$?
echo " END ERROR Running script: ${0##*/}:$1: exited with '${errcode}'."
}
trap 'finish' EXIT
trap 'finish_error $LINENO' ERR
# Influenced by https://dev.to/thiht/shell-scripts-matter
# And see https://github.com/bf4/Notes/wiki/Shell-Scripting
logstamp() { printf "[%s]" "$(TZ='America/Chicago' date +'%Y-%m-%d %H:%M:%S')" ; }
topic() { echo "-----> $(logstamp) $*" ; }
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
# Store which STACK we are running on in the cache to bust the cache if it changes
if [ -f "${CACHE_DIR}/.freetds/STACK" ]; then
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"
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}, STACK=${STACK} CACHED_STACK=${CACHED_STACK} pwd=$(pwd)"
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"
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}"
FREETDS_CACHE_DIR="$CACHE_DIR"
mkdir -p "${FREETDS_CACHE_DIR}"
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"
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.
# Assert $BUILD_TARGET_DIR = $HOME/freetds | $BUILD_DIR/freetds # /app/freetds
BUILD_TARGET_DIR="${BUILD_DIR}/freetds" # /app/freetds
mkdir -p "${BUILD_TARGET_DIR}"
# This is the path that will be used at dyno runtime, and in which we build.
# Assert $APP_TARGET_DIR = $HOME/freetds # /app/freetds
APP_TARGET_DIR="${HOME:-app}/freetds"
mkdir -p "${APP_TARGET_DIR}"
configure_app_env_vars() {
topic "Creating .profile.d entry"
mkdir -p "${BUILD_DIR}/.profile.d"
# These exports must point to /app, because the profile is
# executed in a running dyno, not the buildpack environment
# Assert $APP_TARGET_DIR = $HOME/freetds # /app/freetds
cat <<EOF > "${BUILD_DIR}/.profile.d/freetds.sh"
export PATH="\${HOME}/freetds/bin:\$PATH"
# 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="\${HOME}/freetds"
export LD_LIBRARY_PATH="\${HOME}/freetds/lib:\${LD_LIBRARY_PATH:-/usr/local/lib}"
export LD_RUN_PATH="\${HOME}/freetds/lib:\${LD_RUN_PATH:-/usr/local/lib}"
export LIBRARY_PATH="\${HOME}/freetds/lib:\${LIBRARY_PATH:-/usr/local/lib}"
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=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.
# Assert $BUILD_TARGET_DIR = $HOME/freetds | $BUILD_DIR/freetds # /app/freetds
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}"
# Assert $APP_TARGET_DIR = $HOME/freetds # /app/freetds
export SYBASE="${APP_TARGET_DIR}"
# give environment to later buildpacks
export | grep -E -e ' (PATH|LD_LIBRARY_PATH|LD_RUN_PATH|LIBRARY_PATH|FREETDS_DIR|SYBASE)=' > "${LP_DIR}/export"
echo "configured BUILDPACK env vars:" | indent
indent < "${LP_DIR}/export"
topic "Rewrite package-config files"
# shellcheck disable=SC2038
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'
}
download_and_extract_freetds_archive() {
FREETDS_FILE="$FREETDS_ARCHIVE_NAME.tar.gz"
FREETDS_URL="https://www.freetds.org/files/stable/${FREETDS_FILE}"
# 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
mv "${BUILD_DIR}/build_log-unpack.log" "${BUILD_DIR}/${FREETDS_ARCHIVE_NAME}/"
if [ "$HEROKU_FREETDS_BUILDPACK_DEBUG" = "true" ]; then
debug "$(cat "${BUILD_DIR}/build_log-unpack.log")"
fi
}
build_and_install_freetds() {
topic "Building FreeTDS against OpenSSL $(openssl version)"
( # directory changes in subshells have no effect
cd "${BUILD_DIR}/${FREETDS_ARCHIVE_NAME}"
# We must build at /app/... rather than in the BUILD_DIR because
# the installation hardwires some paths and symlinks. In order for
# these to be in the right location at dyno runtime, we have to
# build using the same path that applies at dyno runtime.
# FreeTDS advises caching the build options as below
# adding --disable-odbc making linking easier and we don't need it
# adding --disable-debug to speed up compile
# As of Oct. 2022, heroku-22 stack currently only works with gnutls.
# Allow this to be toggled off in the future with `export USE_GNUTLS=" "`
# See https://github.com/FreeTDS/freetds/issues/336
# and https://www.freetds.org/userguide/config.html
# for more information.
cat <<EOF > ".build_options"
./configure \
"--prefix=${APP_TARGET_DIR}" \
"${USE_GNUTLS}" \
--disable-odbc \
--disable-debug \
"--with-tdsver=${TDS_VERSION}"
EOF
/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.
{
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"
# shellcheck disable=SC2115
rm -rf "${BUILD_DIR}/${FREETDS_ARCHIVE_NAME}"
)
}
cache_build_artifacts_for_future_deploys() {
topic "Caching FreeTDS installation"
( # directory changes in subshells have no effect
cd "${APP_TARGET_DIR}"
# TODO(BF): Consider removing the documentation before tarring
# rm -rf share
tar cjf "${CACHED_TAR}" . | indent
)
}
main() {
topic "FreeTDS ${FREETDS_VERSION} building in ${BUILD_DIR}"
configure_app_env_vars
if [ ! -f "$CACHED_TAR" ]; then
info "Cached files not found - downloading and unpacking..."
download_and_extract_freetds_archive
build_and_install_freetds
topic "Testing build"
"$APP_TARGET_DIR/bin/tsql" -C | indent
cache_build_artifacts_for_future_deploys
fi
info "Unpacking cached files..."
tar xjf "${CACHED_TAR}" -C "${BUILD_TARGET_DIR}" | indent
configure_buildpack_env_vars
info "Install of FreeTDS ${FREETDS_VERSION} complete"
}
main