DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d38398e5144e)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
#!/bin/sh
self="$0"
dirname_self=$(dirname "$self")

usage() {
  cat <<EOF >&2
Usage: $self [option]

This script applies a whitespace transformation to the commit at HEAD. If no
options are given, then the modified files are left in the working tree.

Options:
  -h, --help     Shows this message
  -n, --dry-run  Shows a diff of the changes to be made.
  --amend        Squashes the changes into the commit at HEAD
                     This option will also reformat the commit message.
  --commit       Creates a new commit containing only the whitespace changes
  --msg-only     Reformat the commit message only, ignore the patch itself.

EOF
  rm -f ${CLEAN_FILES}
  exit 1
}


log() {
  echo "${self##*/}: $@" >&2
}


vpx_style() {
  for f; do
    case "$f" in
      *.h|*.c|*.cc)
        clang-format -i --style=file "$f"
        ;;
    esac
  done
}


apply() {
  [ $INTERSECT_RESULT -ne 0 ] && patch -p1 < "$1"
}


commit() {
  LAST_CHANGEID=$(git show | awk '/Change-Id:/{print $2}')
  if [ -z "$LAST_CHANGEID" ]; then
    log "HEAD doesn't have a Change-Id, unable to generate a new commit"
    exit 1
  fi

  # Build a deterministic Change-Id from the parent's
  NEW_CHANGEID=${LAST_CHANGEID}-styled
  NEW_CHANGEID=I$(echo $NEW_CHANGEID | git hash-object --stdin)

  # Commit, preserving authorship from the parent commit.
  git commit -a -C HEAD > /dev/null
  git commit --amend -F- << EOF
Cosmetic: Fix whitespace in change ${LAST_CHANGEID:0:9}

Change-Id: ${NEW_CHANGEID}
EOF
}


show_commit_msg_diff() {
  if [ $DIFF_MSG_RESULT -ne 0 ]; then
    log "Modified commit message:"
    diff -u "$ORIG_COMMIT_MSG" "$NEW_COMMIT_MSG" | tail -n +3
  fi
}


amend() {
  show_commit_msg_diff
  if [ $DIFF_MSG_RESULT -ne 0 ] || [ $INTERSECT_RESULT -ne 0 ]; then
    git commit -a --amend -F "$NEW_COMMIT_MSG"
  fi
}


diff_msg() {
  git log -1 --format=%B > "$ORIG_COMMIT_MSG"
  "${dirname_self}"/wrap-commit-msg.py \
      < "$ORIG_COMMIT_MSG" > "$NEW_COMMIT_MSG"
  cmp -s "$ORIG_COMMIT_MSG" "$NEW_COMMIT_MSG"
  DIFF_MSG_RESULT=$?
}


# Temporary files
ORIG_DIFF=orig.diff.$$
MODIFIED_DIFF=modified.diff.$$
FINAL_DIFF=final.diff.$$
ORIG_COMMIT_MSG=orig.commit-msg.$$
NEW_COMMIT_MSG=new.commit-msg.$$
CLEAN_FILES="${ORIG_DIFF} ${MODIFIED_DIFF} ${FINAL_DIFF}"
CLEAN_FILES="${CLEAN_FILES} ${ORIG_COMMIT_MSG} ${NEW_COMMIT_MSG}"

# Preconditions
[ $# -lt 2 ] || usage

if ! clang-format -version >/dev/null 2>&1; then
  log "clang-format not found"
  exit 1
fi

if ! git diff --quiet HEAD; then
  log "Working tree is dirty, commit your changes first"
  exit 1
fi

# Need to be in the root
cd "$(git rev-parse --show-toplevel)"

# Collect the original diff
git show > "${ORIG_DIFF}"

# Apply the style guide on new and modified files and collect its diff
for f in $(git diff HEAD^ --name-only -M90 --diff-filter=AM); do
  case "$f" in
    third_party/*) continue;;
  esac
  vpx_style "$f"
done
git diff --no-color --no-ext-diff > "${MODIFIED_DIFF}"

# Intersect the two diffs
"${dirname_self}"/intersect-diffs.py \
    "${ORIG_DIFF}" "${MODIFIED_DIFF}" > "${FINAL_DIFF}"
INTERSECT_RESULT=$?
git reset --hard >/dev/null

# Fixup the commit message
diff_msg

# Handle options
if [ -n "$1" ]; then
  case "$1" in
    -h|--help) usage;;
    -n|--dry-run) cat "${FINAL_DIFF}"; show_commit_msg_diff;;
    --commit) apply "${FINAL_DIFF}"; commit;;
    --amend) apply "${FINAL_DIFF}"; amend;;
    --msg-only) amend;;
    *) usage;;
  esac
else
  apply "${FINAL_DIFF}"
  if ! git diff --quiet; then
    log "Formatting changes applied, verify and commit."
    log "See also: http://www.webmproject.org/code/contribute/conventions/"
    git diff --stat
  fi
fi

rm -f ${CLEAN_FILES}