diff --git a/scripts/pre-commit.hook b/scripts/pre-commit.hook index 27dc9d41e..a03c7285d 100755 --- a/scripts/pre-commit.hook +++ b/scripts/pre-commit.hook @@ -65,45 +65,55 @@ CPPCHECK_OPTS+=" --force $(cppcheck_suppressions) $(cppcheck_build_unmatched)" CPPCHECK_OPTS+=" --cppcheck-build-dir=.out ." RETURN=0 + +# Disallow non-ASCII characters in workspace path +workspace=$(git rev-parse --show-toplevel) +if echo "$workspace" | grep -q "[一-龥]"; then + echo "[!] The workspace path '$workspace' contains non-ASCII characters." >&2 + exit 1 +fi + CLANG_FORMAT=$(which clang-format) if [ $? -ne 0 ]; then - echo "[!] clang-format not installed. Unable to check source file format policy." >&2 - exit 1 + echo "[!] clang-format not installed. Unable to check source file format policy." >&2 + exit 1 fi CPPCHECK=$(which cppcheck) mkdir -p .out if [ $? -ne 0 ]; then - echo "[!] cppcheck not installed. Unable to perform static analysis." >&2 - exit 1 + echo "[!] cppcheck not installed. Unable to perform static analysis." >&2 + exit 1 fi -# Expected Cppcheck version is 1.90+ -# First, Cppcheck 2.x -if [ -z "$($CPPCHECK --version | grep -E '^Cppcheck\s2')" ]; then - # Second, Cppcheck 1.x - CPPCHECK_VER=$($CPPCHECK --version | sed -Ee 's/Cppcheck 1.([0-9]+)/\1/;q') - if [ $CPPCHECK_VER -lt 90 ]; then - echo "[!] cppcheck version must be at least 1.90." >&2 - echo -e " Check 'Developer Info' for building Cppcheck from source:\n" \ - " https://cppcheck.sourceforge.net/devinfo/" >&2 - exit 1 - fi +# Check that cppcheck's version is at least 1.90. +cppcheck_ver=$("$CPPCHECK" --version) +if echo "$cppcheck_ver" | grep -qE '^Cppcheck\s2'; then + : # Version 2.x is acceptable. +else + # For version 1.x, extract the minor version and compare. + minor_version=$(echo "$cppcheck_ver" | sed -Ee 's/Cppcheck 1\.([0-9]+)/\1/;q') + if [ "$minor_version" -lt 90 ]; then + echo "[!] cppcheck version must be at least 1.90." >&2 + echo -e " See Developer Info for building cppcheck from source:\n" + echo -e " https://cppcheck.sourceforge.io/devinfo/" >&2 + exit 1 + fi fi ASPELL=$(which aspell) if [ $? -ne 0 ]; then - echo "[!] aspell not installed. Unable to do spelling check." >&2 - exit 1 + echo "[!] aspell not installed. Unable to do spelling check." >&2 + exit 1 fi if [ -z "$(aspell dump dicts | grep -E '^en$')" ]; then - echo "[!] aspell-en not installed. Unable to do spelling check." >&2 - exit 1 + echo "[!] aspell-en not installed. Unable to do spelling check." >&2 + exit 1 fi DIFF=$(which colordiff) if [ $? -ne 0 ]; then - DIFF=diff + DIFF=diff fi if command -v sha1sum >/dev/null 2>&1; then @@ -115,42 +125,63 @@ else exit 1 fi +# Get staged filenames (added, copied, or modified) into an array. +FILES=($(git diff --cached --name-only --diff-filter=ACM)) +binary_files=() + +for file in "${FILES[@]}"; do + # Get MIME info for the file. + mime_info=$(file --mime "$file") + # Extract a friendly filename (everything before the colon). + name=$(file "$file" | cut -d ":" -f1) + + if echo "$mime_info" | grep -qi binary; then + binary_files+=("$name") + echo "[!] '$name' appears to be a binary blob." + fi +done + +if [ "${#binary_files[@]}" -gt 0 ]; then + echo "WARNING: Binary data found" +fi + FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep -E "\.(c|cpp|h)$") for FILE in $FILES; do - nf=$(git checkout-index --temp $FILE | cut -f 1) - tempdir=$(mktemp -d) || exit 1 - newfile=$(mktemp ${tempdir}/${nf}.XXXXXX) || exit 1 - basename=$(basename $FILE) - - source="${tempdir}/${basename}" - mv $nf $source - cp .clang-format $tempdir - $CLANG_FORMAT $source > $newfile 2>> /dev/null - $DIFF -u -p -B --label="modified $FILE" --label="expected coding style" \ - "${source}" "${newfile}" - r=$? - rm -rf "${tempdir}" - if [ $r != 0 ] ; then - echo "[!] $FILE does not follow the consistent coding style." >&2 - RETURN=1 - fi - if [ $RETURN -eq 1 ]; then - echo "" >&2 - echo "Make sure you indent as the following:" >&2 - echo " clang-format -i $FILE" >&2 - echo - fi + nf=$(git checkout-index --temp $FILE | cut -f 1) + tempdir=$(mktemp -d) || exit 1 + newfile=$(mktemp ${tempdir}/${nf}.XXXXXX) || exit 1 + basename=$(basename $FILE) + + source="${tempdir}/${basename}" + mv $nf $source + cp .clang-format $tempdir + $CLANG_FORMAT $source > $newfile 2>> /dev/null + $DIFF -u -p -B \ + --label="modified $FILE" --label="expected coding style" \ + "${source}" "${newfile}" + r=$? + rm -rf "${tempdir}" + if [ $r != 0 ] ; then + echo "[!] $FILE does not follow the consistent coding style." >&2 + RETURN=1 + fi + if [ $RETURN -eq 1 ]; then + echo "" >&2 + echo "Make sure you indent as the following:" >&2 + echo " clang-format -i $FILE" >&2 + echo + fi done if [ ! -z "${FILES[*]}" ]; then - echo "Following files need to be cleaned up:" - echo "${FILES[*]}" + echo "Following files need to be cleaned up:" + echo "${FILES[*]}" fi $SHA1SUM -c scripts/checksums 2>/dev/null >/dev/null if [ $? -ne 0 ]; then - echo "[!] You are not allowed to change the header file queue.h or list.h" >&2 - exit 1 + echo "[!] You are not allowed to change the header file queue.h or list.h" >&2 + exit 1 fi # Prevent unsafe functions @@ -159,26 +190,26 @@ banned="([^f]gets\()|(sprintf\()|(strcpy\()" status=0 for file in $(git diff --staged --name-only | grep -E "\.(c|cc|cpp|h|hh|hpp)\$") do - filepath="${root}/${file}" - output=$(grep -nrE "${banned}" "${filepath}") - if [ ! -z "${output}" ]; then - echo "Dangerous function detected in ${filepath}" - echo "${output}" - echo - echo "Read 'Common vulnerabilities guide for C programmers' carefully." - echo " https://security.web.cern.ch/security/recommendations/en/codetools/c.shtml" - RETURN=1 - fi + filepath="${root}/${file}" + output=$(grep -nrE "${banned}" "${filepath}") + if [ ! -z "${output}" ]; then + echo "Dangerous function detected in ${filepath}" + echo "${output}" + echo + echo "Read 'Common vulnerabilities guide for C programmers' carefully." + echo " https://security.web.cern.ch/security/recommendations/en/codetools/c.shtml" + RETURN=1 + fi done # static analysis echo "Running static analysis..." $CPPCHECK $CPPCHECK_OPTS >/dev/null if [ $? -ne 0 ]; then - RETURN=1 - echo "" >&2 - echo "Fail to pass static analysis." >&2 - echo + RETURN=1 + echo "" >&2 + echo "Fail to pass static analysis." >&2 + echo fi # non-ASCII filenames are not allowed. @@ -187,12 +218,12 @@ fi if test $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 then - cat <<\EOF + cat <<\EOF ERROR: Attempt to add a non-ASCII file name. This can cause problems if you want to work with people on other platforms. To be portable it is advisable to rename the file. EOF - RETURN=1 + RETURN=1 fi exit $RETURN diff --git a/scripts/pre-push.hook b/scripts/pre-push.hook index eff804353..ce8bb4b52 100755 --- a/scripts/pre-push.hook +++ b/scripts/pre-push.hook @@ -14,10 +14,10 @@ NC='\033[0m' # No Color # Bump copyright year commit=$(git rev-list --skip 1 --grep '^Bump copyright' 0b8be2c15160c216e8b6ec82c99a000e81c0e429...HEAD) if [ x"$commit" != x"50c5ac53d31adf6baac4f8d3db6b3ce2215fee40" ] ; then - echo -e "${RED}ERROR${NC}: This repository is insane." - echo -e "Make sure you did fork from https://github.com/sysprog21/lab0-c recently." - echo "" - exit 1 + echo -e "${RED}ERROR${NC}: This repository is insane." + echo -e "Make sure you did fork from https://github.com/sysprog21/lab0-c recently." + echo "" + exit 1 fi # Show hints @@ -27,24 +27,24 @@ echo "" # only run this if you are pushing to master if [[ $current_branch = $protected_branch ]] ; then - echo -e "${YELLOW}Running pre push to master check...${NC}" - - echo -e "${YELLOW}Trying to build tests project...${NC}" + echo -e "${YELLOW}Running pre push to master check...${NC}" - # build the project - make + echo -e "${YELLOW}Trying to build tests project...${NC}" - # $? is a shell variable which stores the return code from what we just ran - rc=$? - if [[ $rc != 0 ]] ; then - echo -e "${RED}Failed to build the project, please fix this and push again${NC}" - echo "" - exit $rc - fi + # build the project + make - # Everything went OK so we can exit with a zero - echo -e "${GREEN}Pre-push check passed!${NC}" + # $? is a shell variable which stores the return code from what we just ran + rc=$? + if [[ $rc != 0 ]] ; then + echo -e "${RED}Failed to build the project, please fix this and push again${NC}" echo "" + exit $rc + fi + + # Everything went OK so we can exit with a zero + echo -e "${GREEN}Pre-push check passed!${NC}" + echo "" fi exit 0 diff --git a/scripts/prepare-commit-msg.hook b/scripts/prepare-commit-msg.hook index 0a4896164..5a097c558 100755 --- a/scripts/prepare-commit-msg.hook +++ b/scripts/prepare-commit-msg.hook @@ -49,8 +49,8 @@ EOF # Prompt the user about aborting the commit. read -rp "Do you want to abort this commit? (y/N): " answer if [[ "$answer" =~ ^[Yy]$ ]]; then - echo "Commit aborted by user." >&2 - exit 1 + echo "Commit aborted by user." >&2 + exit 1 fi exit 0