Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ src/config
# codespell dictionary
scripts/dictionary/

# marker files for pre-commit and pre-push hooks to check if staged files have been formatted
scripts/.format_markers/

# clangd for nvim lsp
src/.clangd

Expand Down
2 changes: 2 additions & 0 deletions environment_setup/setup_software.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
CURR_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
cd "$CURR_DIR" || exit

git config core.hooksPath "$CURR_DIR/../scripts/githooks"

source util.sh

g_arch=$(uname -m) # Global variable. No function should use this name.
Expand Down
35 changes: 35 additions & 0 deletions scripts/githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/sh

# From the list of files on stdin (separated by newline), return formattable files to stdout
filter_formattable_files() {
grep -E '\.(h|cpp|c|cc|hpp|tpp|proto|py|md|yml)$|/BUILD$'
}

# Output the modification time of a file (or 0 if nonexistent)
get_mtime() {
case "$(uname -s)" in
Darwin*)
stat -f %m "$1" 2> /dev/null || echo 0
;;
*)
# No one will run this on BSD or other Unixes, so this should be fine
stat -c %Y "$1" 2> /dev/null || echo 0
;;
esac
}

# Find repo root, marker for the current branch, and marker mtime (0 if marker does not exist)
toplevel="$(git rev-parse --show-toplevel)"
marker="$toplevel/scripts/.format_markers/$(git rev-parse --abbrev-ref HEAD)"
mtime=$(get_mtime "$marker")

git diff --staged --name-only | filter_formattable_files | while read -r file; do
# Compare marker mtime with file mtime
if [ $mtime -lt $(get_mtime "$toplevel/$file") ]; then
# The file was modified AFTER formatting. Remove the marker to tell the pre-push hook
# that this commit introduces unformatted code.
rm -f "$marker" 2> /dev/null
echo "Warning: Code is unformatted."
break
fi
done
28 changes: 28 additions & 0 deletions scripts/githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

# Prompt user for confirmation at a [y/N] prompt and return 0 when user responds "yes" or "y"
confirm() {
read -r -p "$1 [y/N] " response < /dev/tty
case "$response" in
[yY][eE][sS]|[yY])
return 0
;;
*)
return 1
;;
esac
}

scriptsdir="$(git rev-parse --show-toplevel)/scripts"

# If marker for current branch does not exist
if ! [ -f "$scriptsdir/.format_markers/$(git rev-parse --abbrev-ref HEAD)" ]; then
echo "Warning: Code is unformatted. Please run $scriptsdir/lint_and_format.sh."
if confirm 'Continue without formatting?'; then
echo "Continuing push anyway."
exit 0
else
echo "Aborting push."
exit 1
fi
fi
6 changes: 6 additions & 0 deletions scripts/lint_and_format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,10 @@ run_eof_new_line
run_git_diff_check
run_ansible_lint

# Update markers, telling Git hooks that formatting has been done
# (Per-branch, so switching branches doesn't confuse the hooks)
branch="$(git rev-parse --abbrev-ref HEAD)"
mkdir -p "$CURR_DIR/.format_markers/$(dirname "$branch")"
touch "$CURR_DIR/.format_markers/${branch}"

exit 0