Last active
August 20, 2016 10:27
-
-
Save HaleTom/275f28403828b9b9b93d313990fc94f4 to your computer and use it in GitHub Desktop.
Patch gems then build them
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Usage: gem-patch | |
# Code updates: https://gist.github.com/HaleTom/275f28403828b9b9b93d313990fc94f4 | |
# Features: | |
# Work around `patch` returning non-zero if some patch hunks are already applied | |
# Apply all patches in $patch_dir (in order) to their corresponding gem(s) | |
# Build a gem only after all patches have been applied | |
# Only build the gem if it was patched | |
# Robust error handling | |
patch_dir="$HOME/lib/gem-patch" | |
# Patches are assumed to be made with git patch | |
# Files are to be named gem-name or gem-name.patch-explanation | |
set -e -u | |
shopt -s nullglob # Globs are '' when no files match a pattern | |
gems_dir="$(gem environment gemdir)/gems" | |
if ! compgen -G "$patch_dir/*" > /dev/null; then | |
echo "Couldn't find any patches located in $patch_dir. Quitting." 2>&1 | |
exit 1 | |
fi | |
# Save the current "gemname-1.2.3" so that when it changes to a new one | |
# (ie, all patches have been applied) it can be built only once | |
function build_prev_if_needed { | |
if [[ ${prev_gem_ver:="${gem_ver:=''}"} != "$gem_ver" ]]; then | |
# We've moved on to another gem, build the last one | |
( cd "$gems_dir/$prev_gem_ver" && | |
gem build "${prev_gem_ver%%-[-0-9.]*}.gemspec" | |
) | |
fi | |
prev_gem_ver="$gem_ver" | |
} | |
for patch in "$patch_dir"/*; do | |
gem_name=$(basename "${patch%%[.]*}") found_one=false | |
# $gem_dir becomes "rails-5.0.0.1" from find at end of loop | |
while read -d '' -r gem_dir; do | |
found_one=true | |
# Build the previously seen gem if we've moved on to a new one | |
gem_ver=${gem_dir##$gems_dir/} | |
echo -n "$gem_ver (patch $(basename "$patch")): " | |
# If we could reverse the patch, then it has already been applied; skip it | |
if patch --dry-run --reverse -d "$gem_dir" -fp1 --ignore-whitespace -i "$patch" >/dev/null 2>&1; then | |
echo "skipping (already applied)" | |
continue | |
else # patch not yet applied | |
echo "patching..." | |
# Patch returns non-zero if some hunks have already been applied | |
if ! patch -d "$gem_dir" -fsp1 --ignore-whitespace -i "$patch"; then | |
# Check that the patch was fully applied by pretending to reverse it | |
if patch --dry-run --reverse -d "$gem_dir" -fp1 --ignore-whitespace -i "$patch" >/dev/null 2>&1; then | |
echo "Ignoring failure: hunk(s) were already applied" | |
else | |
echo "Patch failed for $gem_dir" >&2; exit 1; | |
fi | |
fi | |
build_prev_if_needed | |
fi | |
done < <(find "$gems_dir" -maxdepth 1 -type d -regex ".*/$gem_name-[-0-9.]+" -print0) | |
if [[ $found_one != true ]]; then | |
echo "Fatal: Patch file '$(basename "$patch")': Couldn't find any gem sources named $gems_dir/$(basename "$patch")*" >&2; exit 1 | |
fi | |
done # $gem_dir is now blank | |
gem_ver='' | |
build_prev_if_needed |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment