|
| 1 | +#!/bin/bash |
| 2 | +# Auto format changed java files using google-java-format. |
| 3 | +# To install, copy this file into $repo/.git/hooks and remove the .sh extension. |
| 4 | +# Download the google-java-format JAR from |
| 5 | +# https://github.com/google/google-java-format |
| 6 | +# A more mature implementation of this would be a plugin for Yelp's pre-commit library: |
| 7 | +# http://pre-commit.com/ |
| 8 | +echo "Running auto-formatter for any changed Java files" |
| 9 | +echo "(formatting changes will be automatically added to your commit)" |
| 10 | + |
| 11 | +# Grab root directory to help with creating an absolute path for changed files. |
| 12 | +root_dir="$(git rev-parse --show-toplevel)" |
| 13 | +[ -d "${root_dir}" ] || exit 1 |
| 14 | + |
| 15 | +# TODO add your path here. |
| 16 | +jar_base_dir="git_hooks/" |
| 17 | + |
| 18 | +# To avoid any unexpected behavior, we need to "stash" any unstaged changes. |
| 19 | +# We could use "git stash" but the situation gets complicated because we |
| 20 | +# need to make additional changes with the formatter. |
| 21 | +# Here's how we could do this if we didn't need to make additional changes: |
| 22 | +# http://stackoverflow.com/a/20480591 |
| 23 | +# But since we do, we follow the same general pattern as the "pre-commit" lib: |
| 24 | +# https://github.com/pre-commit/pre-commit/blob/master/pre_commit/staged_files_only.py#L15 |
| 25 | +# Basically we just diff the unstaged changes, store the patch, and apply it later. |
| 26 | +# In the future, we should consider migrating to using that library. |
| 27 | +staged_changes_diff=$(mktemp -t format_patch) |
| 28 | +git diff --ignore-submodules --binary --exit-code --no-color > $staged_changes_diff |
| 29 | +if [ $? -eq 1 ]; then |
| 30 | + echo "Found unstaged changes, storing in ${staged_changes_diff}" |
| 31 | + echo "Clearing unstaged changes for formatting, will restore after formatting." |
| 32 | + git checkout -- ${root_dir} |
| 33 | + stored_staged_changes=true |
| 34 | +else |
| 35 | + stored_staged_changes=false |
| 36 | +fi |
| 37 | + |
| 38 | +formatter_jar="${root_dir}/${jar_base_dir}/google-java-format-1.3-all-deps.jar" |
| 39 | +formatter_cmd="java -jar ${formatter_jar}" |
| 40 | +# Format file in-place and use 4-space style (AOSP). |
| 41 | +formatter_args="--replace --aosp" |
| 42 | + |
| 43 | +# filter=ACMR shows only added, changed, modified, or renamed files. |
| 44 | +# Get only java files and prepend the root directory to make the paths absolute. |
| 45 | +changed_java_files=($(git diff --cached --name-only --diff-filter=ACMR \ |
| 46 | + | grep ".*java$" \ |
| 47 | + | sed "s:^:${root_dir}/:")) |
| 48 | +# If we have changed java files, format them! |
| 49 | +if [ ${#changed_java_files[@]} -gt 0 ]; then |
| 50 | + # Do the formatting, stage the changes, and print out which files were changed. |
| 51 | + eval ${formatter_cmd} ${formatter_args} "${changed_java_files[@]}" |
| 52 | + git add "${changed_java_files[@]}" |
| 53 | + echo "${changed_java_files[@]}" | xargs basename | sed "s/^/ Formatting: /" |
| 54 | +fi |
| 55 | + |
| 56 | +echo "Finished formatting." |
| 57 | + |
| 58 | +if $stored_staged_changes ; then |
| 59 | + echo "Restoring unstaged changes" |
| 60 | + git apply "${staged_changes_diff}" |
| 61 | + |
| 62 | + if [ $? -eq 1 ]; then |
| 63 | + echo "Shoot! We failed to re-apply your unstaged changes." |
| 64 | + echo "The patch for these changes is preserved at ${staged_changes_diff}" |
| 65 | + fi |
| 66 | +fi |
0 commit comments