From 2645cb6208ff62cd64deb9862e3eb4d1a81264b3 Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
Date: Fri, 1 Sep 2017 10:49:46 -0400
Subject: FindPatch: Add module to find 'patch' command-line tool

---
 Help/manual/cmake-modules.7.rst     |  1 +
 Help/module/FindPatch.rst           |  1 +
 Help/release/dev/find-patch.rst     |  5 +++
 Modules/FindPatch.cmake             | 68 ++++++++++++++++++++++++++++++++
 Tests/CMakeLists.txt                |  4 ++
 Tests/FindPatch/CMakeLists.txt      |  8 ++++
 Tests/FindPatch/Test/CMakeLists.txt | 77 +++++++++++++++++++++++++++++++++++++
 7 files changed, 164 insertions(+)
 create mode 100644 Help/module/FindPatch.rst
 create mode 100644 Help/release/dev/find-patch.rst
 create mode 100644 Modules/FindPatch.cmake
 create mode 100644 Tests/FindPatch/CMakeLists.txt
 create mode 100644 Tests/FindPatch/Test/CMakeLists.txt

diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index fa6144c..fdc3597 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -182,6 +182,7 @@ All Modules
    /module/FindosgWidget
    /module/FindPackageHandleStandardArgs
    /module/FindPackageMessage
+   /module/FindPatch
    /module/FindPerlLibs
    /module/FindPerl
    /module/FindPHP4
diff --git a/Help/module/FindPatch.rst b/Help/module/FindPatch.rst
new file mode 100644
index 0000000..ba5e910
--- /dev/null
+++ b/Help/module/FindPatch.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPatch.cmake
diff --git a/Help/release/dev/find-patch.rst b/Help/release/dev/find-patch.rst
new file mode 100644
index 0000000..d720c81
--- /dev/null
+++ b/Help/release/dev/find-patch.rst
@@ -0,0 +1,5 @@
+find-patch
+----------
+
+* A :module:`FindPatch` module was added to find the ``patch``
+  command-line executable.
diff --git a/Modules/FindPatch.cmake b/Modules/FindPatch.cmake
new file mode 100644
index 0000000..3ebcae9
--- /dev/null
+++ b/Modules/FindPatch.cmake
@@ -0,0 +1,68 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindPatch
+# ---------
+#
+# The module defines the following variables:
+#
+# ``Patch_EXECUTABLE``
+#   Path to patch command-line executable.
+# ``Patch_FOUND``
+#   True if the patch command-line executable was found.
+#
+# The following :prop_tgt:`IMPORTED` targets are also defined:
+#
+# ``Patch::patch``
+#   The command-line executable.
+#
+# Example usage:
+#
+# .. code-block:: cmake
+#
+#    find_package(Patch)
+#    if(Patch_FOUND)
+#      message("Patch found: ${Patch_EXECUTABLE}")
+#    endif()
+
+set(_doc "Patch command line executable")
+set(_patch_path )
+
+if(CMAKE_HOST_WIN32)
+  set(_patch_path
+    "$ENV{LOCALAPPDATA}/Programs/Git/bin"
+    "$ENV{LOCALAPPDATA}/Programs/Git/usr/bin"
+    "$ENV{APPDATA}/Programs/Git/bin"
+    "$ENV{APPDATA}/Programs/Git/usr/bin"
+    )
+endif()
+
+# First search the PATH
+find_program(Patch_EXECUTABLE
+  NAME patch
+  PATHS ${_patch_path}
+  DOC ${_doc}
+  )
+
+if(CMAKE_HOST_WIN32)
+  # Now look for installations in Git/ directories under typical installation
+  # prefixes on Windows.
+  find_program(Patch_EXECUTABLE
+    NAMES patch
+    PATH_SUFFIXES Git/usr/bin Git/bin GnuWin32/bin
+    DOC ${_doc}
+    )
+endif()
+
+if(Patch_EXECUTABLE AND NOT TARGET Patch::patch)
+  add_executable(Patch::patch IMPORTED)
+  set_property(TARGET Patch::patch PROPERTY IMPORTED_LOCATION ${Patch_EXECUTABLE})
+endif()
+
+unset(_patch_path)
+unset(_doc)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(Patch
+                                  REQUIRED_VARS Patch_EXECUTABLE)
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 516bc89..3dfc8eb 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1484,6 +1484,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     add_subdirectory(FindPNG)
   endif()
 
+  if(CMake_TEST_FindPatch)
+    add_subdirectory(FindPatch)
+  endif()
+
   if(CMake_TEST_FindProtobuf)
     add_subdirectory(FindProtobuf)
   endif()
diff --git a/Tests/FindPatch/CMakeLists.txt b/Tests/FindPatch/CMakeLists.txt
new file mode 100644
index 0000000..541f5bd
--- /dev/null
+++ b/Tests/FindPatch/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_test(NAME FindPatch.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindPatch/Test"
+  "${CMake_BINARY_DIR}/Tests/FindPatch/Test"
+  ${build_generator_args}
+  --build-options ${build_options}
+)
diff --git a/Tests/FindPatch/Test/CMakeLists.txt b/Tests/FindPatch/Test/CMakeLists.txt
new file mode 100644
index 0000000..f4cd621
--- /dev/null
+++ b/Tests/FindPatch/Test/CMakeLists.txt
@@ -0,0 +1,77 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindPatch VERSION 1.0 LANGUAGES NONE)
+
+macro(_check)
+  if(NOT EXISTS "${Patch_EXECUTABLE}")
+    message(FATAL_ERROR "Failed to lookup Patch_EXECUTABLE [${Patch_EXECUTABLE}]")
+  endif()
+
+  if(NOT DEFINED PATCH_FOUND)
+    message(FATAL_ERROR "Variable PATCH_FOUND is not defined")
+  endif()
+
+  # Is import target available ?
+  if(NOT TARGET Patch::patch)
+    message(FATAL_ERROR "Target Patch::patch is not defined")
+  endif()
+
+  # Check Patch::patch imported location
+  get_property(_imported_location TARGET Patch::patch PROPERTY IMPORTED_LOCATION)
+  if(NOT "${Patch_EXECUTABLE}" STREQUAL "${_imported_location}")
+    message(FATAL_ERROR "\
+Patch_EXECUTABLE is expected to be equal to Patch::patch IMPORTED_LOCATION
+  Patch_EXECUTABLE [${Patch_EXECUTABLE}]
+  Patch::patch IMPORTED_LOCATION [${_imported_location}]
+")
+  endif()
+
+endmacro()
+
+find_package(Patch REQUIRED)
+_check()
+
+# Calling twice should not fail
+find_package(Patch REQUIRED)
+_check()
+
+add_custom_target(TestPatchVersion ALL
+  COMMAND ${Patch_EXECUTABLE} -v
+  )
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/QUOTE.txt.baseline"
+[=[Because it's there.
+- George Mallory, 1923
+]=]
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/QUOTE.txt" "Because it's there.\n")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/quote-add-author.patch"
+[=[diff --git a/QUOTE.txt b/QUOTE.txt
+index b36681d..68059b3 100644
+--- a/QUOTE.txt
++++ b/QUOTE.txt
+@@ -1 +1,2 @@
+ Because it's there.
++- George Mallory
+]=]
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/quote-add-date.patch"
+[=[diff --git a/QUOTE.txt b/QUOTE.txt
+index 68059b3..c6f30c2 100644
+--- a/QUOTE.txt
++++ b/QUOTE.txt
+@@ -1,2 +1,2 @@
+ Because it's there.
+-- George Mallory
++- George Mallory, 1923
+]=]
+)
+
+add_custom_target(TestPatch ALL
+  COMMAND ${Patch_EXECUTABLE} -p1 -i quote-add-author.patch
+  COMMAND Patch::patch -p1 -i quote-add-date.patch
+  COMMAND ${CMAKE_COMMAND} -E compare_files QUOTE.txt QUOTE.txt.baseline
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+  )
-- 
cgit v0.12