Skip to content

Commit

Permalink
pre-commit: Install a local pre-commit hook during configuration
Browse files Browse the repository at this point in the history
Install a `.git/hooks/pre-commit` hook into the local repository.
Rather than trying to do all the checks directly, make it a simple
launcher that loads a configured pre-commit hook from the checkout in
the work tree.  This will allow us to add checks to pre-commit over
time without re-installing the hook into an unversioned location.
  • Loading branch information
bradking committed Jul 21, 2016
1 parent 08c4ca3 commit cbaca1e
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .hooks-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# CMake installs a pre-commit hook that reads this configuration
# file to get the location of the real hook to run.
[hooks "chain"]
pre-commit = cmake/git/pre-commit.bash
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ message(STATUS CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX})
include(ExternalProject)
find_package(Git REQUIRED)

include(cmake/git/hooks.cmake)
drake_setup_git_hooks()

function(drake_forceupdate proj)
# CMake < 3.6 forget to mark the update step as "ALWAYS" when an explicit
# UPDATE_COMMAND is used. Add our own "ALWAYS" step to force updates.
Expand Down
37 changes: 37 additions & 0 deletions cmake/git/hooks.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
function(drake_setup_git_hooks)
set(_git_dir "${PROJECT_SOURCE_DIR}/.git")
if(NOT IS_DIRECTORY "${_git_dir}")
return()
endif()

# Use a comment to hold the launcher version number.
set(_hook_version_regex "Drake pre-commit hook launcher version '([0-9.]+)'")
set(_in "${PROJECT_SOURCE_DIR}/cmake/git/pre-commit.in")
set(_out "${_git_dir}/hooks/pre-commit")

# Extract version of our hook launcher.
file(STRINGS "${_in}" _in_version_line REGEX "${_hook_version_regex}" LIMIT_INPUT 1024)
if(_in_version_line MATCHES "${_hook_version_regex}")
set(_in_version "${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR "Failed to extract version from '${_in}'")
endif()

# Extract version of hook launcher currently installed.
if(EXISTS "${_out}")
file(STRINGS "${_out}" _out_version_line REGEX "${_hook_version_regex}" LIMIT_INPUT 1024)
if(_out_version_line MATCHES "${_hook_version_regex}")
set(_out_version "${CMAKE_MATCH_1}")
else()
set(_out_version 1000000) # hook has unexpected content, do not replace it
endif()
else()
set(_out_version 0)
endif()

# Install the hook launcher, but replace an existing launcher
# only if it is an older version of our launcher.
if(_in_version VERSION_GREATER _out_version)
configure_file("${_in}" "${_out}" @ONLY)
endif()
endfunction()
1 change: 1 addition & 0 deletions cmake/git/pre-commit.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#!/usr/bin/env bash
27 changes: 27 additions & 0 deletions cmake/git/pre-commit.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Drake pre-commit hook launcher version '1'.

# Look up a configured pre-commit hook to call.
#
# Read local configuration of a custom pre-commit hook. Keep all our
# hooks configuration in a single "hooks" section since .git/config
# may have a lot of other content.
chain="$(git config --get hooks.chain-pre-commit)" ||
# Read project configuration from the source tree. In this dedicated
# file we can have more sections, so keep all "chain" hooks in one.
chain="$(git config -f .hooks-config --get hooks.chain.pre-commit)" ||
chain=""

# Choose a prefix needed to launch the hook without searching the PATH.
case "$chain" in
'') exit 0 ;;
'/'*) prefix="" ;;
'[A-Za-z]:/'*) prefix="" ;;
'.'*) prefix="" ;;
*) prefix="./" ;;
esac

# Chain to the configured hook.
if test -x "$prefix$chain" ; then
exec "$prefix$chain" "$@"
fi

0 comments on commit cbaca1e

Please sign in to comment.