1#!/usr/bin/env bash
2# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3# If clang_format_diff.py command is not specfied, we assume we are able to
4# access directly without any path.
5if [ -z $CLANG_FORMAT_DIFF ]
6then
7CLANG_FORMAT_DIFF="clang-format-diff.py"
8fi
9
10# Check clang-format-diff.py
11if ! which $CLANG_FORMAT_DIFF &> /dev/null
12then
13  echo "You didn't have clang-format-diff.py and/or clang-format available in your computer!"
14  echo "You can download clang-format-diff.py by running: "
15  echo "    curl --location http://goo.gl/iUW1u2 -o ${CLANG_FORMAT_DIFF}"
16  echo "You can download clang-format by running:"
17  echo "    brew install clang-format"
18  echo "  Or"
19  echo "    apt install clang-format"
20  echo "  This might work too:"
21  echo "    yum install git-clang-format"
22  echo "Then, move both files (i.e. ${CLANG_FORMAT_DIFF} and clang-format) to some directory within PATH=${PATH}"
23  echo "and make sure ${CLANG_FORMAT_DIFF} is executable."
24  exit 128
25fi
26
27# Check argparse, a library that clang-format-diff.py requires.
28python 2>/dev/null << EOF
29import argparse
30EOF
31
32if [ "$?" != 0 ]
33then
34  echo "To run clang-format-diff.py, we'll need the library "argparse" to be"
35  echo "installed. You can try either of the follow ways to install it:"
36  echo "  1. Manually download argparse: https://pypi.python.org/pypi/argparse"
37  echo "  2. easy_install argparse (if you have easy_install)"
38  echo "  3. pip install argparse (if you have pip)"
39  exit 129
40fi
41
42# TODO(kailiu) following work is not complete since we still need to figure
43# out how to add the modified files done pre-commit hook to git's commit index.
44#
45# Check if this script has already been added to pre-commit hook.
46# Will suggest user to add this script to pre-commit hook if their pre-commit
47# is empty.
48# PRE_COMMIT_SCRIPT_PATH="`git rev-parse --show-toplevel`/.git/hooks/pre-commit"
49# if ! ls $PRE_COMMIT_SCRIPT_PATH &> /dev/null
50# then
51#   echo "Would you like to add this script to pre-commit hook, which will do "
52#   echo -n "the format check for all the affected lines before you check in (y/n):"
53#   read add_to_hook
54#   if [ "$add_to_hook" == "y" ]
55#   then
56#     ln -s `git rev-parse --show-toplevel`/build_tools/format-diff.sh $PRE_COMMIT_SCRIPT_PATH
57#   fi
58# fi
59set -e
60
61uncommitted_code=`git diff HEAD`
62
63# If there's no uncommitted changes, we assume user are doing post-commit
64# format check, in which case we'll try to check the modified lines vs. the
65# facebook/rocksdb.git master branch. Otherwise, we'll check format of the
66# uncommitted code only.
67if [ -z "$uncommitted_code" ]
68then
69  # Attempt to get name of facebook/rocksdb.git remote.
70  [ "$FORMAT_REMOTE" ] || FORMAT_REMOTE="$(git remote -v | grep 'facebook/rocksdb.git' | head -n 1 | cut -f 1)"
71  # Fall back on 'origin' if that fails
72  [ "$FORMAT_REMOTE" ] || FORMAT_REMOTE=origin
73  # Use master branch from that remote
74  [ "$FORMAT_UPSTREAM" ] || FORMAT_UPSTREAM="$FORMAT_REMOTE/master"
75  # Get the common ancestor with that remote branch. Everything after that
76  # common ancestor would be considered the contents of a pull request, so
77  # should be relevant for formatting fixes.
78  FORMAT_UPSTREAM_MERGE_BASE="$(git merge-base "$FORMAT_UPSTREAM" HEAD)"
79  # Get the differences
80  diffs=$(git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -p 1)
81else
82  # Check the format of uncommitted lines,
83  diffs=$(git diff -U0 HEAD | $CLANG_FORMAT_DIFF -p 1)
84fi
85
86if [ -z "$diffs" ]
87then
88  echo "Nothing needs to be reformatted!"
89  exit 0
90fi
91
92# Highlight the insertion/deletion from the clang-format-diff.py's output
93COLOR_END="\033[0m"
94COLOR_RED="\033[0;31m"
95COLOR_GREEN="\033[0;32m"
96
97echo -e "Detect lines that doesn't follow the format rules:\r"
98# Add the color to the diff. lines added will be green; lines removed will be red.
99echo "$diffs" |
100  sed -e "s/\(^-.*$\)/`echo -e \"$COLOR_RED\1$COLOR_END\"`/" |
101  sed -e "s/\(^+.*$\)/`echo -e \"$COLOR_GREEN\1$COLOR_END\"`/"
102
103if [[ "$OPT" == *"-DTRAVIS"* ]]
104then
105  exit 1
106fi
107
108echo -e "Would you like to fix the format automatically (y/n): \c"
109
110# Make sure under any mode, we can read user input.
111exec < /dev/tty
112read to_fix
113
114if [ "$to_fix" != "y" ]
115then
116  exit 1
117fi
118
119# Do in-place format adjustment.
120if [ -z "$uncommitted_code" ]
121then
122  git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -i -p 1
123else
124  git diff -U0 HEAD^ | $CLANG_FORMAT_DIFF -i -p 1
125fi
126echo "Files reformatted!"
127
128# Amend to last commit if user do the post-commit format check
129if [ -z "$uncommitted_code" ]; then
130  echo -e "Would you like to amend the changes to last commit (`git log HEAD --oneline | head -1`)? (y/n): \c"
131  read to_amend
132
133  if [ "$to_amend" == "y" ]
134  then
135    git commit -a --amend --reuse-message HEAD
136    echo "Amended to last commit"
137  fi
138fi
139