1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FindGit
6-------
7
8The module defines the following variables:
9
10``GIT_EXECUTABLE``
11  Path to Git command-line client.
12``Git_FOUND``, ``GIT_FOUND``
13  True if the Git command-line client was found.
14``GIT_VERSION_STRING``
15  The version of Git found.
16
17.. versionadded:: 3.14
18  The module defines the following ``IMPORTED`` targets (when
19  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
20
21``Git::Git``
22  Executable of the Git command-line client.
23
24Example usage:
25
26.. code-block:: cmake
27
28   find_package(Git)
29   if(Git_FOUND)
30     message("Git found: ${GIT_EXECUTABLE}")
31   endif()
32#]=======================================================================]
33
34# Look for 'git' or 'eg' (easy git)
35#
36set(git_names git eg)
37
38# Prefer .cmd variants on Windows unless running in a Makefile
39# in the MSYS shell.
40#
41if(CMAKE_HOST_WIN32)
42  if(NOT CMAKE_GENERATOR MATCHES "MSYS")
43    set(git_names git.cmd git eg.cmd eg)
44    # GitHub search path for Windows
45    file(GLOB github_path
46      "$ENV{LOCALAPPDATA}/Github/PortableGit*/cmd"
47      "$ENV{LOCALAPPDATA}/Github/PortableGit*/bin"
48      )
49    # SourceTree search path for Windows
50    set(_git_sourcetree_path "$ENV{LOCALAPPDATA}/Atlassian/SourceTree/git_local/bin")
51  endif()
52endif()
53
54# First search the PATH and specific locations.
55find_program(GIT_EXECUTABLE
56  NAMES ${git_names}
57  PATHS ${github_path} ${_git_sourcetree_path}
58  DOC "Git command line client"
59  )
60
61if(CMAKE_HOST_WIN32)
62  # Now look for installations in Git/ directories under typical installation
63  # prefixes on Windows.  Exclude PATH from this search because VS 2017's
64  # command prompt happens to have a PATH entry with a Git/ subdirectory
65  # containing a minimal git not meant for general use.
66  find_program(GIT_EXECUTABLE
67    NAMES ${git_names}
68    PATH_SUFFIXES Git/cmd Git/bin
69    NO_SYSTEM_ENVIRONMENT_PATH
70    DOC "Git command line client"
71    )
72endif()
73
74mark_as_advanced(GIT_EXECUTABLE)
75
76unset(git_names)
77unset(_git_sourcetree_path)
78
79if(GIT_EXECUTABLE)
80  # Avoid querying the version if we've already done that this run. For
81  # projects that use things like ExternalProject or FetchContent heavily,
82  # this saving can be measurable on some platforms.
83  #
84  # This is an internal property, projects must not try to use it.
85  # We don't want this stored in the cache because it might still change
86  # between CMake runs, but it shouldn't change during a run for a given
87  # git executable location.
88  set(__doGitVersionCheck TRUE)
89  get_property(__gitVersionProp GLOBAL
90    PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
91  )
92  if(__gitVersionProp)
93    list(GET __gitVersionProp 0 __gitExe)
94    list(GET __gitVersionProp 1 __gitVersion)
95    if(__gitExe STREQUAL GIT_EXECUTABLE AND NOT __gitVersion STREQUAL "")
96      set(GIT_VERSION_STRING "${__gitVersion}")
97      set(__doGitVersionCheck FALSE)
98    endif()
99    unset(__gitExe)
100    unset(__gitVersion)
101  endif()
102  unset(__gitVersionProp)
103
104  if(__doGitVersionCheck)
105    execute_process(COMMAND ${GIT_EXECUTABLE} --version
106                    OUTPUT_VARIABLE git_version
107                    ERROR_QUIET
108                    OUTPUT_STRIP_TRAILING_WHITESPACE)
109    if (git_version MATCHES "^git version [0-9]")
110      string(REPLACE "git version " "" GIT_VERSION_STRING "${git_version}")
111      set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
112        "${GIT_EXECUTABLE};${GIT_VERSION_STRING}"
113      )
114    endif()
115    unset(git_version)
116  endif()
117  unset(__doGitVersionCheck)
118
119  get_property(_findgit_role GLOBAL PROPERTY CMAKE_ROLE)
120  if(_findgit_role STREQUAL "PROJECT" AND NOT TARGET Git::Git)
121    add_executable(Git::Git IMPORTED)
122    set_property(TARGET Git::Git PROPERTY IMPORTED_LOCATION "${GIT_EXECUTABLE}")
123  endif()
124  unset(_findgit_role)
125endif()
126
127include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
128find_package_handle_standard_args(Git
129                                  REQUIRED_VARS GIT_EXECUTABLE
130                                  VERSION_VAR GIT_VERSION_STRING)
131