Skip to content

Instantly share code, notes, and snippets.

@memory
Created May 29, 2012 19:35
Show Gist options
  • Save memory/2830217 to your computer and use it in GitHub Desktop.
Save memory/2830217 to your computer and use it in GitHub Desktop.
UNCLEAN
#!/bin/bash -e
# just in case (some parts of the ruby build will honor this...)
unset DESTDIR
export PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin:/usr/local/sbin
export INSTALLPREFIX=/export/disk0/wb/bin/ruby-env
export ENVNAME=$1
export SYSTEM=$(uname -s)
export REPODIR=$(git rev-parse --show-toplevel)
export WORKDIR=${REPODIR}/ruby/env-builder
export DATADIR=${WORKDIR}/${ENVNAME}
export RUBYVERSIONFILE=${DATADIR}/ruby
export GEMSVERSIONFILE=${DATADIR}/gems
export BUILDROOT=${REPODIR}/bin/target/ruby-env/${ENVNAME}
export INSTALLROOT=${INSTALLPREFIX}/${ENVNAME}
# we install into buildroot/installroot, and then later on we can
# slice off the build root path to get a valid install root
export BUILDPATH="${BUILDROOT}${INSTALLROOT}"
if [ -z "$ENVNAME" ]; then
echo "No env name specified, bailing."
exit 1
fi
if [ "$SYSTEM" != 'Linux' ]; then
echo "Building on non-linux systems is not supported, bailing."
exit 1
fi
if ! [ -d ${REPODIR}/ruby/env-builder/${ENVNAME} ]; then
echo "you don't seem to have set up ${ENVNAME} (needs at least a ruby and gems file)"
exit 1
fi
if ! (type -P symlinks); then
echo "the symlinks command was not found, maybe you need to install it?"
exit 1
fi
RUBYFULLVER=$(cat ${RUBYVERSIONFILE})
RUBYMAJOR=$(echo ${RUBYFULLVER} | cut -d. -f1-2)
# it is not safe to rebuild in place :(
### echo removing old build dir
rm -rf "${BUILDROOT}"
mkdir -p "${BUILDROOT}"/src
pushd ${BUILDROOT}/src
wget http://ftp.ruby-lang.org/pub/ruby/${RUBYMAJOR}/ruby-${RUBYFULLVER}.tar.gz
echo "building ruby into ${BUILDPATH}"
tar xvf ruby-${RUBYFULLVER}.tar.gz
cd ruby-${RUBYFULLVER}
# the --enable-load-relative flag is crucial
./configure \
--prefix=${BUILDPATH} \
--enable-shared \
--enable-load-relative \
--disable-install-doc \
--disable-install-rdoc \
--disable-install-capi
make -j3
make install
popd
# optionally, install our gems
if [ -f ${GEMSVERSIONFILE} ]; then
while read line; do
${BUILDPATH}/bin/gem install --no-ri --no-rdoc -V $line
done < ${GEMSVERSIONFILE}
if (grep -q passenger ${GEMSVERSIONFILE}); then
# TODO(n): figure out some way to trigger the apache vs nginx build
${BUILDPATH}/bin/passenger-install-apache2-module -a
fi
fi
# don't bother packaging up the source tree
rm -rf "${BUILDROOT}/src"
# and now, make everything relocatable, which is a harder trick than you'd
# think.
# Step One: fix up all file paths inside plaintext files.
#
# in re that ugly perl inline: would anyone be crazy enough to embed spaces,
# quotes or backslashes into a ruby library path/file name? answer: it's
# ruby, what do _you_ think? (and the sed version is even more eye-gouging)
#
# shell quoting kung-fu: want to cram both ' and " into a string? It
# works like this:
#
# # foo="'"'"'
# # echo $foo
# '"
#
# # bar='"'"'"
# # echo $bar
# "'
#
# so:
#
# perl -pe 's#([ "`'"'"'\\])#\\$1#g'
# ^ ^^^^^^^ ^
# q DDqqDqq q
#
# D=data q=quote delimiter
#
# ...which is to say, if the shell weren't mangling things:
#
# perl -pe s#([ "`'\\])#\\$1#g
echo fixing build paths in text files
txtfiles=$(find ${BUILDROOT} -type f -print0 |xargs -0 grep ${BUILDROOT} | \
egrep -v 'Binary file' | \
cut -d: -f1 | sort | uniq | \
perl -pe 's#([ "`'"'"'\\])#\\$1#g' | \
xargs)
if [ -n "$txtfiles" ]; then
echo found bad build paths in $txtfiles
perl -pi -e"s#${BUILDROOT}##g" $txtfiles
fi
# Step Two: fix up all file paths inside binary files(!)
#
# the horror: rvm+ruby's build produces elf executables with absolute RPATH
# values for the executables themselves and also any linked shared libraries
# inside the ruby/rvm hierarchy, e.g. libruby.so. Luckily, the full RPATH is
# BUILDROOT+INSTALLROOT, so we can use a completely sleazy perl one-liner to
# shear off BUILDROOT, and replace it with INSTALLROOT(foo), right-padded with
# nulls to the length of BUILDROOT.
#
# elvis wept.
echo fixing file paths in binary files
binfiles=$(find ${BUILDROOT} -type f -print0 |xargs -0 grep ${BUILDROOT} | \
egrep 'Binary file' | \
cut -d' ' -f3- | sed -e 's/ matches//' | sort | uniq | \
perl -pe 's#([ "`'"'"'\\])#\\$1#g' | \
xargs)
if [ -n "$binfiles" ]; then
echo found bad paths in $binfiles
# note that -0 sets IFS to \0, letting us treat an arbitrary chunk of
# binary data like a "line".
#
# note that we also handle the ugly case of someone embedding a colon-
# separated path list inside a null-terminated string.
#
# to put it mildly, this may not be portable to all possible unix variants.
echo $binfiles | xargs \
perl -0 -pi -e \
'$match=$ENV{BUILDROOT}; $count = s#$match##g; $pad = "\0" x ($count * length($match)); s#$#$pad#e;'
fi
# Step Three: make all internal symlinks relative.
echo making all symlinks relative
# oy, symlinks fails with a malloc error if you feed it too long an initial path
pushd ${BUILDPATH}
symlinks -r -c .
popd
echo "Et Voila!"
popd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment