From 91053cdf7b24e769e8bee21606bbf4558af11bab Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 15 Aug 2012 10:09:43 -0400 Subject: [PATCH] ExternalProject: Add Mercurial (hg) repository support Add options HG_REPOSITORY and HG_TAG to specify an external project hosted in a Mercurial repository. Teach ExternalProject to clone the repository and update from it. Extend the ExternalProject test to try a Mercurial repository when hg is available. --- Modules/ExternalProject.cmake | 128 ++++++++++++++++++++++++++- Tests/ExternalProject/CMakeLists.txt | 75 +++++++++++++++- Tests/ExternalProject/hgrepo.tgz | Bin 0 -> 2011 bytes 3 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 Tests/ExternalProject/hgrepo.tgz diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index f0471ff2c..cd77ba4e2 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -21,6 +21,8 @@ # [SVN_TRUST_CERT 1 ] # Trust the Subversion server site certificate # [GIT_REPOSITORY url] # URL of git repo # [GIT_TAG tag] # Git branch name, commit id or tag +# [HG_REPOSITORY url] # URL of mercurial repo +# [HG_TAG tag] # Mercurial branch name, commit id or tag # [URL /.../src.tgz] # Full path or URL of source # [URL_MD5 md5] # MD5 checksum of file at URL # [TIMEOUT seconds] # Time allowed for file download operations @@ -331,6 +333,67 @@ endif() endfunction() +function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile) + file(WRITE ${script_filename} +"if(\"${hg_tag}\" STREQUAL \"\") + message(FATAL_ERROR \"Tag for hg checkout should not be empty.\") +endif() + +set(run 0) + +if(\"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\") + set(run 1) +endif() + +if(NOT run) + message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\") + return() +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 \"${hg_EXECUTABLE}\" clone \"${hg_repository}\" \"${src_name}\" + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) +if(error_code) + message(FATAL_ERROR \"Failed to clone repository: '${hg_repository}'\") +endif() + +execute_process( + COMMAND \"${hg_EXECUTABLE}\" update ${hg_tag} + WORKING_DIRECTORY \"${work_dir}/${src_name}\" + RESULT_VARIABLE error_code + ) +if(error_code) + message(FATAL_ERROR \"Failed to checkout tag: '${hg_tag}'\") +endif() + +# Complete success, update the script-last-run stamp file: +# +execute_process( + COMMAND \${CMAKE_COMMAND} -E copy + \"${hgclone_infofile}\" + \"${hgclone_stampfile}\" + WORKING_DIRECTORY \"${work_dir}/${src_name}\" + RESULT_VARIABLE error_code + ) +if(error_code) + message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${hgclone_stampfile}'\") +endif() + +" +) + +endfunction() + function(_ep_write_downloadfile_script script_filename remote local timeout md5) if(timeout) @@ -1027,6 +1090,7 @@ function(_ep_add_download_command name) 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(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY ) get_property(url TARGET ${name} PROPERTY _EP_URL) # TODO: Perhaps file:// should be copied to download dir before extraction. @@ -1148,6 +1212,46 @@ function(_ep_add_download_command name) 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(hg_repository) + find_package(Hg) + if(NOT HG_EXECUTABLE) + message(FATAL_ERROR "error: could not find hg for clone of ${name}") + endif() + + get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG) + if(NOT hg_tag) + set(hg_tag "tip") + endif() + + # For the download step, and the hg clone operation, only the repository + # should be recorded in a configured RepositoryInfo file. If the repo + # changes, the clone script should be run again. But if only the tag + # changes, avoid running the clone script again. Let the 'always' running + # update step checkout the new tag. + # + set(repository ${hg_repository}) + set(module) + set(tag) + configure_file( + "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in" + "${stamp_dir}/${name}-hginfo.txt" + @ONLY + ) + + get_filename_component(src_name "${source_dir}" NAME) + get_filename_component(work_dir "${source_dir}" PATH) + + # Since hg 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 hg clone. + # + _ep_write_hgclone_script(${tmp_dir}/${name}-hgclone.cmake ${source_dir} + ${HG_EXECUTABLE} ${hg_repository} ${hg_tag} ${src_name} ${work_dir} + ${stamp_dir}/${name}-hginfo.txt ${stamp_dir}/${name}-hgclone-lastrun.txt + ) + set(comment "Performing download step (hg clone) for '${name}'") + set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake) + list(APPEND depends ${stamp_dir}/${name}-hginfo.txt) elseif(url) get_filename_component(work_dir "${source_dir}" PATH) get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5) @@ -1196,7 +1300,7 @@ function(_ep_add_download_command name) else() _ep_is_dir_empty("${source_dir}" empty) if(${empty}) - message(SEND_ERROR "error: no download info for '${name}' -- please specify existing/non-empty SOURCE_DIR or one of URL, CVS_REPOSITORY and CVS_MODULE, SVN_REPOSITORY, GIT_REPOSITORY or DOWNLOAD_COMMAND") + message(SEND_ERROR "error: no download info for '${name}' -- please specify existing/non-empty SOURCE_DIR or one of URL, CVS_REPOSITORY and CVS_MODULE, SVN_REPOSITORY, GIT_REPOSITORY, HG_REPOSITORY or DOWNLOAD_COMMAND") endif() endif() @@ -1226,6 +1330,7 @@ function(_ep_add_update_command name) 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(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY ) set(work_dir) set(comment) @@ -1280,6 +1385,27 @@ function(_ep_add_update_command name) COMMAND ${GIT_EXECUTABLE} submodule update --recursive ) set(always 1) + elseif(hg_repository) + if(NOT HG_EXECUTABLE) + message(FATAL_ERROR "error: could not find hg for pull of ${name}") + endif() + set(work_dir ${source_dir}) + set(comment "Performing update step (hg pull) for '${name}'") + get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG) + if(NOT hg_tag) + set(hg_tag "tip") + endif() + if("${HG_VERSION_STRING}" STREQUAL "2.1") + message(WARNING "Mercurial 2.1 does not distinguish an empty pull from a failed pull: + http://mercurial.selenic.com/wiki/UpgradeNotes#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X + http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656 +Update to Mercurial >= 2.1.1. +") + endif() + set(cmd ${HG_EXECUTABLE} pull + COMMAND ${HG_EXECUTABLE} update ${hg_tag} + ) + set(always 1) endif() get_property(log TARGET ${name} PROPERTY _EP_LOG_UPDATE) diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt index 7a7626199..33ffe2ede 100644 --- a/Tests/ExternalProject/CMakeLists.txt +++ b/Tests/ExternalProject/CMakeLists.txt @@ -6,6 +6,7 @@ include(ExternalProject) find_package(CVS) find_package(Subversion) find_package(Git) +find_package(Hg) option(ExternalProjectTest_USE_FOLDERS "Enable folder grouping in IDEs." ON) if(ExternalProjectTest_USE_FOLDERS) @@ -511,6 +512,76 @@ if(do_git_tests) set_property(TARGET ${proj} PROPERTY FOLDER "GIT") endif() +set(do_hg_tests 0) + +if(HG_EXECUTABLE) + set(do_hg_tests 1) +endif() + +if(do_hg_tests) + set(local_hg_repo "../../LocalRepositories/HG") + + # Unzip/untar the hg repository in our source folder so that other + # projects below may use it to test hg args of ExternalProject_Add + # + set(proj SetupLocalHGRepository) + ExternalProject_Add(${proj} + SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/HG + URL ${CMAKE_CURRENT_SOURCE_DIR}/hgrepo.tgz + BUILD_COMMAND "" + CONFIGURE_COMMAND "${HG_EXECUTABLE}" --version + INSTALL_COMMAND "" + ) + set_property(TARGET ${proj} + PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing") + + + # hg by commit id: + # + set(proj TutorialStep1-HG-byhash) + ExternalProject_Add(${proj} + HG_REPOSITORY "${local_hg_repo}" + HG_TAG dd2ce38a6b8a + UPDATE_COMMAND "" + CMAKE_GENERATOR "${CMAKE_GENERATOR}" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + INSTALL_COMMAND "" + DEPENDS "SetupLocalHGRepository" + ) + set_property(TARGET ${proj} PROPERTY FOLDER "HG") + + # hg by explicit branch/tag name: + # + set(proj TutorialStep1-HG-bytag) + ExternalProject_Add(${proj} + HG_REPOSITORY "${local_hg_repo}" + HG_TAG "default" + UPDATE_COMMAND "" + CMAKE_GENERATOR "${CMAKE_GENERATOR}" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + INSTALL_COMMAND "" + DEPENDS "SetupLocalHGRepository" + ) + set_property(TARGET ${proj} PROPERTY FOLDER "HG") + + # Live hg / tip (no HG_TAG): + # + # Mercurial 2.1 does not distinguish an empty pull from a failed pull, + # so do not run the test with that version. + if(NOT "${HG_VERSION_STRING}" STREQUAL "2.1") + set(proj TutorialStep1-HG-tip) + ExternalProject_Add(${proj} + HG_REPOSITORY "${local_hg_repo}" + CMAKE_GENERATOR "${CMAKE_GENERATOR}" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + INSTALL_COMMAND "" + DEPENDS "SetupLocalHGRepository" + LOG_UPDATE 1 + ) + set_property(TARGET ${proj} PROPERTY FOLDER "HG") + endif() +endif() + # Test the testable built/installed products: # @@ -581,5 +652,5 @@ 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}'") +message(STATUS "do_git_tests='${do_git_tests}' GIT_EXECUTABLE='${GIT_EXECUTABLE}'") +message(STATUS "do_hg_tests='${do_hg_tests}' HG_EXECUTABLE='${HG_EXECUTABLE}'") diff --git a/Tests/ExternalProject/hgrepo.tgz b/Tests/ExternalProject/hgrepo.tgz new file mode 100644 index 0000000000000000000000000000000000000000..0d75ce22f004241b0e29975fac94cb62d2df9b12 GIT binary patch literal 2011 zcmV<12PF6(iwFRz?krFM1ItJ+N-fCOXP_l800MJU0}yR!ZfXvp&A@yZU@$Z?Ff=wa zGdD6ZW-u@`GBYw^P%x#btDvB?xFoSiL4hHuC^1DZJ2NjGhdM&?Llk5{;$JT#opxz} z^!PV61`3VFKOF#4{FmmX>5bZv+%KG&M0aWl%7nt~0QM z5gz|3scDI&IVA(_j8QN^04e{cWEKJQLP;vs?I4){P0`DLQv+kO(fmIOMggq>QvRn! z)ei;)^S>c_{x>lJ773&IpAG<8|8otrJ4V640Hpk1lv-GtS(I8#bvp>=eNk*zdeol%4 zD6J^uBv$5^j*b`%4}d=YM~guKLiyhax&03r|1&o?9?k!Q2_%Au|4;yA3Wt;e8w{C= zInMccX_@JI8G4y{=xTUMplbAzD=N?>`J8=KO5|Ih(o#6PGOpt2o=%6~&sBlPkg$Q&*I=>bv_OA_@_i(+8o-+&7& zj-`x8NFo>RU{M2u+{C=hwAA7fC>OaqVKCaI9Fzbf|AXU}x^|FW{+k+`jL!el1z?YV zw7g9rAXNUFnwg@;Kag!UI{!}}zzBp81~9uZ`ND)@E%o-oe>+Nq&g<@5wf+^?Zryz$ zhuZCswO7n(4fM@EV!)oZpXEM@05O;{_gy-96$isH@Q-xs@o+~0ky zdsy`xa+pf?OQtW&*d*yY^$8V=jiAE2A3mk-uM37@^NM6Ik|^-=9HChxu~_B=V(tT z)8XLKf{TXR-|5Bd@Yc!9l$__#d#0()!bUK9g78kKmvfB{wq9q*m({J4zjprM)^2m_ zT|8XtOJ}WI`}$yq%nAPQe%qGPH-_;7?D;=FIX)NIB#6&JY7>wT25cO>cZu%40?}G#%n$DSg-Zi@(*h#vi6EOr4#-A4;%0teg9MB z+Jg&mr{*(%4=j7JWbF!Rk2#BU3a>lN=21^{?s)GP)qC*54%NEz=j~5#64pOqom(Pq z<@ZC%WMR{j!XVwQBEIW4eNUOC%nz*cn07Gw(js3;>*mzv4{cAjm?k)FcRDrWaJ=3= z{)d}CZdvm{>#x7wv%q~aPD@R<#<4pITv!m`5%5~6*s1ouH7B=7 z%I?nZ{<)*d>g~I=hnbvKGA1qUT~Pj^rQ(5;!4<#OyyZ_bfVPf}& ztGUvz-45P&%(;Iw)Mm;X(~^^!CoT#KybEB{57XTg@yP!EVaEgS2D!1F&tG7!V7CRqO8Ua?CvNmnZ+ zVD_wwhXl6F2>xr;gsi<{&gJXj8YewMJ*X7GLSN(Lne*CV9%sA*HT-ln zPoDAC5A!&!AH<=lds6?D&zXloexAOk&v>_TA8Fso##;UB_tD>0RX^D^EfU1b4=g@^ znSZz4gdNP{;tbE1TTG;9XpA_3k^gBh3rHyc8yljv{|(K|%tzP%&<7y$e=iU(g9*d( z|6QHOUD;i}KVJLzSzXc#=%~C9`U6>e#T?g8Z?0wo0f+CFu6_bC#!@XoTnpC9DA@rAF(rTkl&(<~0%9S&ZP^!`m~?cVq2r&!qk zzP8gfp$QwC#n^6VJLE{2+MWOIvHOkNsukB2V(N(I|z>d8ldNYQ}faFzw`lE$A9sR{$d;Z z9Ua;ox&TZ4k2H!;9Y99?Z)!5S{)avQwfw!;#j<-w^v5HW`)ZH>zWj9SzU|lEzkB%0EYoWZQzhdH1#gx4 zrrx})P1k44+z=|#R{1AAyf69D6er`SBFt0RLVaCkb&6jN7U3>%nq5Ebj`3l7hTA9@ t1*2dTjDk@x3P!;w7zLwX6pVsVFbYP&C>RB!U=$2;006v9oEHF4001Nd2%P`` literal 0 HcmV?d00001