Skip to content

Commit 565d2f5

Browse files
authored
Replace apt-get rlwrap installation with shim (#187)
1 parent a001e12 commit 565d2f5

File tree

4 files changed

+68
-39
lines changed

4 files changed

+68
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [Unreleased]
44

5+
* Replace `apt-get` `rlwrap` installation with shim. ([#187](https://github.com/heroku/heroku-buildpack-clojure/pull/187))
56

67
## [v92] - 2025-09-11
78

bin/compile

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,19 @@ install_jdk "${BUILD_DIR}"
3535
# Install Node.js if needed
3636
detect_and_install_nodejs "${BUILD_DIR}"
3737

38-
# install rlwrap binary, always needed for clj command, and also on old lein 1.x
39-
install_rlwrap "${BUILD_DIR}" "${CACHE_DIR}"
38+
# Install rlwrap shim for Leiningen 1.x and clj REPLs.
39+
# rlwrap is technically a dependency for both, but it only enhances REPL functionality
40+
# with line editing and command history. This shim allows clj and lein 1.x to run without
41+
# errors, but does not provide actual readline capabilities. Most users don't use REPLs
42+
# in a Heroku context. Users can install their own rlwrap via the APT buildpack and this
43+
# shim will not interfere.
44+
mkdir -p "${BUILD_DIR}/.heroku/bin"
45+
cp "${BP_DIR}/opt/rlwrap" "${BUILD_DIR}/.heroku/bin/rlwrap"
46+
47+
# To ensure the cache created by older Clojure buildpack versions doesn't stay around indefinitely, we explicitly
48+
# delete these old directories. This will speed up subsequent app builds since it will take less time to restore
49+
# the cache before each build.
50+
rm -rf "${CACHE_DIR}/clojure-bp-apt"
4051

4152
# Run clojure install script (clojure / clj may be needed from leiningen for newer cli tools)
4253
CLOJURE_CLI_VERSION="${CLOJURE_CLI_VERSION:-1.10.0.411}"
@@ -179,7 +190,7 @@ PROFILE_PATH="${BUILD_DIR}/.profile.d/clojure.sh"
179190
mkdir -p "$(dirname "${PROFILE_PATH}")"
180191
{
181192
echo "export LEIN_NO_DEV=\"\${LEIN_NO_DEV:-yes}\""
182-
echo "export PATH=\"\$HOME/.heroku/nodejs/bin:\$HOME/.heroku/clj/bin:\$HOME/.jdk/bin:\$HOME/.lein/bin:\$PATH\""
193+
echo "export PATH=\"\$HOME/.heroku/bin:\$HOME/.heroku/nodejs/bin:\$HOME/.heroku/clj/bin:\$HOME/.jdk/bin:\$HOME/.lein/bin:\$PATH\""
183194
echo "export RING_ENV=\"\${RING_ENV:-production}\""
184195
} >>"${PROFILE_PATH}"
185196

lib/lein.sh

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,39 +20,3 @@ function is_lein_2() {
2020
return 1
2121
fi
2222
}
23-
24-
function install_rlwrap() {
25-
local buildDir="${1:?}"
26-
local cacheDir="${2:?}"
27-
28-
APT_CACHE_DIR="${cacheDir}/clojure-bp-apt/cache"
29-
APT_STATE_DIR="${cacheDir}/clojure-bp-apt/state"
30-
APT_OPTIONS="-o debug::nolocking=true -o dir::cache=${APT_CACHE_DIR} -o dir::state=${APT_STATE_DIR}"
31-
32-
mkdir -p "${APT_CACHE_DIR}/archives/partial"
33-
mkdir -p "${APT_STATE_DIR}/lists/partial"
34-
35-
echo "-----> Installing rlwrap... "
36-
# shellcheck disable=SC2086
37-
apt-get ${APT_OPTIONS} update | indent
38-
# shellcheck disable=SC2086
39-
apt-get ${APT_OPTIONS} -y -d install --reinstall rlwrap | indent
40-
41-
mkdir -p "${buildDir}/.profile.d"
42-
cat <<EOF >"${buildDir}/.profile.d/rlwrap.sh"
43-
export PATH="\$HOME/.heroku/apt/usr/bin:\$PATH"
44-
export LD_LIBRARY_PATH="\$HOME/.heroku/apt/usr/lib/x86_64-linux-gnu:\$HOME/.heroku/apt/usr/lib/i386-linux-gnu:\$HOME/.heroku/apt/usr/lib:\$LD_LIBRARY_PATH"
45-
export LIBRARY_PATH="\$HOME/.heroku/apt/usr/lib/x86_64-linux-gnu:\$HOME/.heroku/apt/usr/lib/i386-linux-gnu:\$HOME/.heroku/apt/usr/lib:\$LIBRARY_PATH"
46-
export INCLUDE_PATH="\$HOME/.heroku/apt/usr/include:\$INCLUDE_PATH"
47-
export CPATH="\$INCLUDE_PATH"
48-
export CPPPATH="\$INCLUDE_PATH"
49-
export PKG_CONFIG_PATH="\$HOME/.heroku/apt/usr/lib/x86_64-linux-gnu/pkgconfig:\$HOME/.heroku/apt/usr/lib/i386-linux-gnu/pkgconfig:\$HOME/.heroku/apt/usr/lib/pkgconfig:\$PKG_CONFIG_PATH"
50-
export PYTHONPATH="\$HOME/.heroku/apt/usr/lib/python2.7/dist-packages"
51-
export SCREENDIR="\$HOME/.heroku/apt/var/run/screen"
52-
EOF
53-
54-
for DEB in "${APT_CACHE_DIR}/archives/"*.deb; do
55-
dpkg -x "${DEB}" "${buildDir}/.heroku/apt/"
56-
done
57-
chmod +x "${buildDir}/.heroku/apt/usr/bin/"*
58-
}

opt/rlwrap

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
# This script provides a fallback when rlwrap is not installed, allowing Leiningen 1.x and clj REPLs to function
6+
# without requiring the buildpack to install rlwrap as a dependency. Using a REPL on Heroku is rare and typically
7+
# only needed for one-off debugging. Installing rlwrap for all users incurs a cost in build time and slug size
8+
# for very little benefit to the majority of apps. Users who frequently use Leiningen 1.x or clj REPLs can opt-in
9+
# to full readline support by installing rlwrap via the APT buildpack.
10+
11+
# Find the first rlwrap binary on PATH that is not this script. Used to make sure that users who have installed
12+
# rlwrap use the real binary instead of this script.
13+
RLWRAP_BIN=$(command -v -a rlwrap 2>/dev/null | grep -v "^${BASH_SOURCE[0]}$" | head -1 || true)
14+
15+
if [[ -n "${RLWRAP_BIN}" ]]; then
16+
exec "${RLWRAP_BIN}" "${@}"
17+
else
18+
cat >&2 <<-EOF
19+
Warning: Using minimal rlwrap replacement. Command history and line editing are not available.
20+
To enable full readline support, add the APT buildpack and create an Aptfile:
21+
22+
1. heroku buildpacks:add --index 1 heroku-community/apt
23+
2. echo "rlwrap" > Aptfile
24+
3. git add Aptfile && git commit -m "Add rlwrap support"
25+
4. git push heroku main
26+
27+
EOF
28+
29+
# Strip rlwrap options, leaving only the wrapped command.
30+
while [[ "${1:-}" == -* ]]; do
31+
# Options that require an argument need an additional shift.
32+
case "${1:-}" in
33+
-a | --always-readline | -b | --break-chars | -C | --command-name | \
34+
-D | --history-no-dupes | -f | --file | -g | --forget-matching | \
35+
-H | --history-filename | -l | --logfile | -O | --only-cook | \
36+
-P | --pre-given | -q | --quote-characters | -s | --histsize | \
37+
-S | --substitute-prompt | -t | --set-term-name | \
38+
-w | --wait-before-prompt | -z | --filter)
39+
shift
40+
;;
41+
-m | --multi-line | -p | --prompt-colour)
42+
# Optional argument: only shift if not another option.
43+
if [[ "${1:-}" != -* ]]; then
44+
shift
45+
fi
46+
;;
47+
esac
48+
49+
shift
50+
done
51+
52+
exec "${@}"
53+
fi

0 commit comments

Comments
 (0)