Ver Fonte

Add git support to ExternalProject.

Requires at least version 1.6.5 of a git client for
git submodule update --recursive use.
David Cole há 15 anos atrás
pai
commit
670e16af2d

+ 129 - 0
Modules/ExternalProject.cmake

@@ -16,6 +16,8 @@
 #    [CVS_TAG tag]               # Tag to checkout from CVS repo
 #    [SVN_REPOSITORY url]        # URL of Subversion repo
 #    [SVN_REVISION rev]          # Revision to checkout from Subversion repo
+#    [GIT_REPOSITORY url]        # URL of git repo
+#    [GIT_TAG tag]               # Git branch name, commit id or tag
 #    [URL /.../src.tgz]          # Full path or URL of source
 #    [TIMEOUT seconds]           # Time allowed for file download operations
 #   #--Update/Patch step----------
@@ -203,6 +205,62 @@ define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
   )
 
 
+function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag src_name work_dir)
+  file(WRITE ${script_filename}
+"if(\"${git_tag}\" STREQUAL \"\")
+  message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
+endif()
+
+execute_process(
+  COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" clone \"${git_repository}\" \"${src_name}\"
+  WORKING_DIRECTORY \"${work_dir}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to clone repository: '${git_repository}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag}
+  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" submodule init
+  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\")
+endif()
+
+execute_process(
+  COMMAND \"${git_EXECUTABLE}\" submodule update --recursive
+  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+  RESULT_VARIABLE error_code
+  )
+if(error_code)
+  message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
+endif()
+
+"
+)
+
+endfunction(_ep_write_gitclone_script)
+
+
 function(_ep_write_downloadfile_script script_filename remote local timeout)
   if(timeout)
     set(timeout_args TIMEOUT ${timeout})
@@ -609,6 +667,19 @@ function(_ep_add_mkdir_command name)
 endfunction(_ep_add_mkdir_command)
 
 
+function(_ep_get_git_version git_EXECUTABLE git_version_var)
+  if(git_EXECUTABLE)
+    execute_process(
+      COMMAND "${git_EXECUTABLE}" --version
+      OUTPUT_VARIABLE ov
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      )
+    string(REGEX REPLACE "^git version (.+)$" "\\1" version "${ov}")
+    set(${git_version_var} "${version}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+
 function(_ep_add_download_command name)
   ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
 
@@ -616,6 +687,7 @@ function(_ep_add_download_command name)
   get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
+  get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
   get_property(url TARGET ${name} PROPERTY _EP_URL)
 
   # TODO: Perhaps file:// should be copied to download dir before extraction.
@@ -676,6 +748,47 @@ function(_ep_add_download_command name)
     set(comment "Performing download step (SVN checkout) for '${name}'")
     set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision} ${src_name})
     list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
+  elseif(git_repository)
+    find_program(git_EXECUTABLE NAMES git.cmd git eg.cmd eg DOC "git command line client")
+    mark_as_advanced(git_EXECUTABLE)
+    if(NOT git_EXECUTABLE)
+      message(FATAL_ERROR "error: could not find git for clone of ${name}")
+    endif()
+
+    # The git submodule update '--recursive' flag requires git >= v1.6.5
+    #
+    _ep_get_git_version("${git_EXECUTABLE}" git_version)
+    if(git_version VERSION_LESS 1.6.5)
+      message(FATAL_ERROR "error: git version 1.6.5 or later required for 'git submodule update --recursive': git_version='${git_version}'")
+    endif()
+
+    get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
+    if(NOT git_tag)
+      set(git_tag "master")
+    endif()
+
+    set(repository ${git_repository})
+    set(module)
+    set(tag ${git_tag})
+    configure_file(
+      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+      "${stamp_dir}/${name}-gitinfo.txt"
+      @ONLY
+      )
+
+    get_filename_component(src_name "${source_dir}" NAME)
+    get_filename_component(work_dir "${source_dir}" PATH)
+
+    # Since git clone doesn't succeed if the non-empty source_dir exists,
+    # create a cmake script to invoke as download command.
+    # The script will delete the source directory and then call git clone.
+    #
+    _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
+      ${git_EXECUTABLE} ${git_repository} ${git_tag} ${src_name} ${work_dir}
+      )
+    set(comment "Performing download step (git clone) for '${name}'")
+    set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
+    list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
   elseif(url)
     get_filename_component(work_dir "${source_dir}" PATH)
     set(repository "external project URL")
@@ -734,6 +847,7 @@ function(_ep_add_update_command name)
   get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
+  get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
 
   set(work_dir)
   set(comment)
@@ -759,6 +873,21 @@ function(_ep_add_update_command name)
     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
     set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision})
     set(always 1)
+  elseif(git_repository)
+    if(NOT git_EXECUTABLE)
+      message(FATAL_ERROR "error: could not find git for fetch of ${name}")
+    endif()
+    set(work_dir ${source_dir})
+    set(comment "Performing update step (git fetch) for '${name}'")
+    get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
+    if(NOT git_tag)
+      set(git_tag "master")
+    endif()
+    set(cmd ${git_EXECUTABLE} fetch
+      COMMAND ${git_EXECUTABLE} checkout ${git_tag}
+      COMMAND ${git_EXECUTABLE} submodule update --recursive
+      )
+    set(always 1)
   endif()
 
   ExternalProject_Add_Step(${name} update

+ 69 - 2
Tests/ExternalProject/CMakeLists.txt

@@ -5,6 +5,7 @@ include(ExternalProject)
 
 find_package(CVS)
 find_package(Subversion)
+find_program(git_EXECUTABLE NAMES git.cmd git eg.cmd eg DOC "git command line client")
 
 set(base "${CMAKE_BINARY_DIR}/CMakeExternals")
 set(binary_base "${base}/Build")
@@ -37,8 +38,6 @@ if(NOT DEFINED can_build_tutorial_step5)
   endif()
 endif()
 
-message(STATUS "can_build_tutorial_step5='${can_build_tutorial_step5}'")
-
 
 # Empty projects that test all the known ExternalProject_Add argument key words:
 #
@@ -301,6 +300,67 @@ if(do_svn_tests)
 endif()
 
 
+set(do_git_tests 0)
+
+if(git_EXECUTABLE)
+  set(do_git_tests 1)
+endif()
+
+
+if(do_git_tests)
+  set(local_git_repo "${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT")
+
+  # Unzip/untar the git repository in our source folder so that other
+  # projects below may use it to test git args of ExternalProject_Add
+  #
+  set(proj SetupLocalGITRepository)
+  ExternalProject_Add(${proj}
+    SOURCE_DIR ${local_git_repo}
+    URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo.tgz
+    BUILD_COMMAND ""
+    CONFIGURE_COMMAND ${git_EXECUTABLE} --version
+    INSTALL_COMMAND ""
+  )
+
+  # git by commit id:
+  #
+  set(proj TutorialStep1-GIT-byhash)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    GIT_TAG d1970730310fe8bc07e73f15dc570071f9f9654a
+    UPDATE_COMMAND ""
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+  )
+
+  # git by explicit branch/tag name:
+  #
+  set(proj TutorialStep1-GIT-bytag)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    GIT_TAG "origin/master"
+    UPDATE_COMMAND ""
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+  )
+
+  # Live git / master (no GIT_TAG):
+  #
+  set(proj TutorialStep1-GIT-master)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+  )
+endif()
+
+
 # Test the testable built/installed products:
 #
 enable_testing()
@@ -365,3 +425,10 @@ if(can_build_tutorial_step5)
   set_property(TEST TutorialStep5-InstallTreeTest
     APPEND PROPERTY LABELS Step5 InstallTree)
 endif()
+
+
+message(STATUS "can_build_tutorial_step5='${can_build_tutorial_step5}'")
+message(STATUS "do_cvs_tests='${do_cvs_tests}'")
+message(STATUS "do_svn_tests='${do_svn_tests}'")
+message(STATUS "do_git_tests='${do_git_tests}'")
+message(STATUS "git_EXECUTABLE='${git_EXECUTABLE}'")

BIN
Tests/ExternalProject/gitrepo.tgz