format-diff.sh 4.7 KB

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