From 11bdc2b1a13f8bd435cdee271ce435cf533e1aa8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 8 Jun 2010 15:58:39 -0400 Subject: [PATCH 1/3] Generalize CTest.Update* test dashboard script helpers Teach (create|run)_dashboard_script macros to treat the argument as the name of a build tree. Append '.cmake' to generate the dashboard script name. This allows future re-use of the macros for multiple test scripts. --- Tests/CTestUpdateBZR.cmake.in | 4 ++-- Tests/CTestUpdateCVS.cmake.in | 4 ++-- Tests/CTestUpdateCommon.cmake | 12 ++++++------ Tests/CTestUpdateGIT.cmake.in | 4 ++-- Tests/CTestUpdateHG.cmake.in | 4 ++-- Tests/CTestUpdateSVN.cmake.in | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Tests/CTestUpdateBZR.cmake.in b/Tests/CTestUpdateBZR.cmake.in index 7f90b5004..c654f477a 100644 --- a/Tests/CTestUpdateBZR.cmake.in +++ b/Tests/CTestUpdateBZR.cmake.in @@ -142,7 +142,7 @@ run_dashboard_command_line(user-binary) # Test initial checkout and update with a dashboard script. message("Running CTest Dashboard Script...") -create_dashboard_script(dashboard.cmake +create_dashboard_script(dash-binary "# bzr command configuration set(CTEST_BZR_COMMAND \"${BZR}\") set(CTEST_CHECKOUT_COMMAND @@ -150,4 +150,4 @@ set(CTEST_CHECKOUT_COMMAND ") # Run the dashboard script with CTest. -run_dashboard_script(dashboard.cmake) +run_dashboard_script(dash-binary) diff --git a/Tests/CTestUpdateCVS.cmake.in b/Tests/CTestUpdateCVS.cmake.in index 6f31a2cf9..a04673e25 100644 --- a/Tests/CTestUpdateCVS.cmake.in +++ b/Tests/CTestUpdateCVS.cmake.in @@ -147,7 +147,7 @@ run_dashboard_command_line(user-binary) # Test initial checkout and update with a dashboard script. message("Running CTest Dashboard Script...") -create_dashboard_script(dashboard.cmake +create_dashboard_script(dash-binary "# CVS command configuration set(CTEST_CVS_COMMAND \"${CVS}\") set(CTEST_CVS_UPDATE_OPTIONS -dAP) @@ -156,4 +156,4 @@ set(CTEST_CHECKOUT_COMMAND ") # Run the dashboard script with CTest. -run_dashboard_script(dashboard.cmake) +run_dashboard_script(dash-binary) diff --git a/Tests/CTestUpdateCommon.cmake b/Tests/CTestUpdateCommon.cmake index 266f4b3bd..c62505c8f 100644 --- a/Tests/CTestUpdateCommon.cmake +++ b/Tests/CTestUpdateCommon.cmake @@ -165,15 +165,15 @@ endfunction(create_build_tree) #----------------------------------------------------------------------------- # Function to write the dashboard test script. -function(create_dashboard_script name custom_text) +function(create_dashboard_script bin_dir custom_text) # Write the dashboard script. - file(WRITE ${TOP}/dashboard.cmake + file(WRITE ${TOP}/${bin_dir}.cmake "# CTest Dashboard Script set(CTEST_DASHBOARD_ROOT \"${TOP}\") set(CTEST_SITE test.site) set(CTEST_BUILD_NAME dash-test) set(CTEST_SOURCE_DIRECTORY \${CTEST_DASHBOARD_ROOT}/dash-source) -set(CTEST_BINARY_DIRECTORY \${CTEST_DASHBOARD_ROOT}/dash-binary) +set(CTEST_BINARY_DIRECTORY \${CTEST_DASHBOARD_ROOT}/${bin_dir}) ${custom_text} # Start a dashboard and run the update step ctest_start(Experimental) @@ -203,15 +203,15 @@ endfunction(run_dashboard_command_line) #----------------------------------------------------------------------------- # Function to run the dashboard through a script -function(run_dashboard_script name) +function(run_dashboard_script bin_dir) run_child( WORKING_DIRECTORY ${TOP} - COMMAND ${CMAKE_CTEST_COMMAND} -S ${name} -V + COMMAND ${CMAKE_CTEST_COMMAND} -S ${bin_dir}.cmake -V ) # Verify the updates reported by CTest. list(APPEND UPDATE_MAYBE Updated{subdir}) - check_updates(dash-binary + check_updates(${bin_dir} Updated{foo.txt} Updated{bar.txt} Updated{zot.txt} diff --git a/Tests/CTestUpdateGIT.cmake.in b/Tests/CTestUpdateGIT.cmake.in index f0a577084..d4f6d0448 100644 --- a/Tests/CTestUpdateGIT.cmake.in +++ b/Tests/CTestUpdateGIT.cmake.in @@ -230,7 +230,7 @@ run_dashboard_command_line(user-binary) # Test initial checkout and update with a dashboard script. message("Running CTest Dashboard Script...") -create_dashboard_script(dashboard.cmake +create_dashboard_script(dash-binary "# git command configuration set(CTEST_GIT_COMMAND \"${GIT}\") set(CTEST_GIT_UPDATE_OPTIONS) @@ -253,4 +253,4 @@ execute_process( ") # Run the dashboard script with CTest. -run_dashboard_script(dashboard.cmake) +run_dashboard_script(dash-binary) diff --git a/Tests/CTestUpdateHG.cmake.in b/Tests/CTestUpdateHG.cmake.in index f2e5f8387..543ddd92a 100644 --- a/Tests/CTestUpdateHG.cmake.in +++ b/Tests/CTestUpdateHG.cmake.in @@ -145,7 +145,7 @@ run_dashboard_command_line(user-binary) # Test initial checkout and update with a dashboard script. message("Running CTest Dashboard Script...") -create_dashboard_script(dashboard.cmake +create_dashboard_script(dash-binary "# hg command configuration set(CTEST_HG_COMMAND \"${HG}\") set(CTEST_HG_UPDATE_OPTIONS) @@ -160,4 +160,4 @@ execute_process( ") # Run the dashboard script with CTest. -run_dashboard_script(dashboard.cmake) +run_dashboard_script(dash-binary) diff --git a/Tests/CTestUpdateSVN.cmake.in b/Tests/CTestUpdateSVN.cmake.in index 509597b0f..97b2a07fe 100644 --- a/Tests/CTestUpdateSVN.cmake.in +++ b/Tests/CTestUpdateSVN.cmake.in @@ -127,7 +127,7 @@ run_dashboard_command_line(user-binary) # Test initial checkout and update with a dashboard script. message("Running CTest Dashboard Script...") -create_dashboard_script(dashboard.cmake +create_dashboard_script(dash-binary "# Subversion command configuration set(CTEST_SVN_COMMAND \"${SVN}\") set(CTEST_SVN_UPDATE_OPTIONS @@ -137,4 +137,4 @@ set(CTEST_CHECKOUT_COMMAND ") # Run the dashboard script with CTest. -run_dashboard_script(dashboard.cmake) +run_dashboard_script(dash-binary) From 2eae651acc45c303008d9870a6a4f9da3d8bcf19 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 8 Jun 2010 16:12:28 -0400 Subject: [PATCH 2/3] ctest_update: Support custom Git update command Define CTest configuration variable CTEST_GIT_UPDATE_CUSTOM to set a custom command line for updating Git-managed source trees. --- Modules/DartConfiguration.tcl.in | 1 + Source/CTest/cmCTestGIT.cxx | 51 ++++++++++++++++++++++---- Source/CTest/cmCTestGIT.h | 4 ++ Source/CTest/cmCTestUpdateCommand.cxx | 2 + Tests/CTestUpdateGIT.cmake.in | 53 ++++++++++++++++++++++----- 5 files changed, 95 insertions(+), 16 deletions(-) diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in index 85b4138ba..51f514fde 100644 --- a/Modules/DartConfiguration.tcl.in +++ b/Modules/DartConfiguration.tcl.in @@ -49,6 +49,7 @@ SVNUpdateOptions: @SVN_UPDATE_OPTIONS@ # Git options GITCommand: @GITCOMMAND@ GITUpdateOptions: @GIT_UPDATE_OPTIONS@ +GITUpdateCustom: @CTEST_GIT_UPDATE_CUSTOM@ # Generic update command UpdateCommand: @UPDATE_COMMAND@ diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index f5ba36120..5972d39bc 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -85,7 +85,7 @@ void cmCTestGIT::NoteNewRevision() } //---------------------------------------------------------------------------- -bool cmCTestGIT::UpdateImpl() +bool cmCTestGIT::UpdateByPull() { const char* git = this->CommandLineTool.c_str(); @@ -114,14 +114,51 @@ bool cmCTestGIT::UpdateImpl() OutputLogger out(this->Log, "pull-out> "); OutputLogger err(this->Log, "pull-err> "); - if(this->RunUpdateCommand(&git_pull[0], &out, &err)) + return this->RunUpdateCommand(&git_pull[0], &out, &err); +} + +//---------------------------------------------------------------------------- +bool cmCTestGIT::UpdateByCustom(std::string const& custom) +{ + std::vector git_custom_command; + cmSystemTools::ExpandListArgument(custom, git_custom_command, true); + std::vector git_custom; + for(std::vector::const_iterator + i = git_custom_command.begin(); i != git_custom_command.end(); ++i) { - char const* git_submodule[] = {git, "submodule", "update", 0}; - OutputLogger out2(this->Log, "submodule-out> "); - OutputLogger err2(this->Log, "submodule-err> "); - return this->RunChild(git_submodule, &out2, &err2); + git_custom.push_back(i->c_str()); } - return false; + git_custom.push_back(0); + + OutputLogger custom_out(this->Log, "custom-out> "); + OutputLogger custom_err(this->Log, "custom-err> "); + return this->RunUpdateCommand(&git_custom[0], &custom_out, &custom_err); +} + +//---------------------------------------------------------------------------- +bool cmCTestGIT::UpdateInternal() +{ + std::string custom = this->CTest->GetCTestConfiguration("GITUpdateCustom"); + if(!custom.empty()) + { + return this->UpdateByCustom(custom); + } + return this->UpdateByPull(); +} + +//---------------------------------------------------------------------------- +bool cmCTestGIT::UpdateImpl() +{ + if(!this->UpdateInternal()) + { + return false; + } + + const char* git = this->CommandLineTool.c_str(); + char const* git_submodule[] = {git, "submodule", "update", 0}; + OutputLogger submodule_out(this->Log, "submodule-out> "); + OutputLogger submodule_err(this->Log, "submodule-err> "); + return this->RunChild(git_submodule, &submodule_out, &submodule_err); } //---------------------------------------------------------------------------- diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h index 0b6ad2eee..bdb2c6269 100644 --- a/Source/CTest/cmCTestGIT.h +++ b/Source/CTest/cmCTestGIT.h @@ -32,6 +32,10 @@ private: virtual void NoteNewRevision(); virtual bool UpdateImpl(); + bool UpdateByPull(); + bool UpdateByCustom(std::string const& custom); + bool UpdateInternal(); + void LoadRevisions(); void LoadModifications(); diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 571745d78..841434911 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -51,6 +51,8 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() "GITCommand", "CTEST_GIT_COMMAND"); this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS"); + this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, + "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM"); this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "HGCommand", "CTEST_HG_COMMAND"); this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, diff --git a/Tests/CTestUpdateGIT.cmake.in b/Tests/CTestUpdateGIT.cmake.in index d4f6d0448..95461bb96 100644 --- a/Tests/CTestUpdateGIT.cmake.in +++ b/Tests/CTestUpdateGIT.cmake.in @@ -192,15 +192,18 @@ run_child( #----------------------------------------------------------------------------- # Go back to before the changes so we can test updating. -message("Backing up to revision 1...") -run_child( - WORKING_DIRECTORY ${TOP}/user-source - COMMAND ${GIT} reset --hard master~2 - ) -run_child( - WORKING_DIRECTORY ${TOP}/user-source - COMMAND ${GIT} submodule update - ) +macro(rewind_source src_dir) + message("Backing up to revision 1...") + run_child( + WORKING_DIRECTORY ${TOP}/${src_dir} + COMMAND ${GIT} reset --hard origin/master~2 + ) + run_child( + WORKING_DIRECTORY ${TOP}/${src_dir} + COMMAND ${GIT} submodule update + ) +endmacro(rewind_source) +rewind_source(user-source) # Make sure pull does not try to rebase (which does not work with # modified files) even if ~/.gitconfig sets "branch.master.rebase". @@ -226,6 +229,22 @@ UpdateCommand: ${GIT} # Run the dashboard command line interface. run_dashboard_command_line(user-binary) +rewind_source(user-source) +modify_content(user-source) + +message("Running CTest Dashboard Command Line (custom update)...") + +# Create the user build tree. +create_build_tree(user-source user-binary-custom) +file(APPEND ${TOP}/user-binary-custom/CTestConfiguration.ini + "# GIT command configuration +UpdateCommand: ${GIT} +GITUpdateCustom: ${GIT};pull;origin;master +") + +# Run the dashboard command line interface. +run_dashboard_command_line(user-binary-custom) + #----------------------------------------------------------------------------- # Test initial checkout and update with a dashboard script. message("Running CTest Dashboard Script...") @@ -254,3 +273,19 @@ execute_process( # Run the dashboard script with CTest. run_dashboard_script(dash-binary) + +rewind_source(dash-source) + +#----------------------------------------------------------------------------- +# Test custom update with a dashboard script. +message("Running CTest Dashboard Script (custom update)...") + +create_dashboard_script(dash-binary-custom + "# git command configuration +set(CTEST_GIT_COMMAND \"${GIT}\") +set(CTEST_GIT_UPDATE_OPTIONS) +set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin master) +") + +# Run the dashboard script with CTest. +run_dashboard_script(dash-binary-custom) From c3781efb28a35f54ed6306354330734994f2c8b1 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 8 Jun 2010 16:37:04 -0400 Subject: [PATCH 3/3] ctest_update: Support Git upstream branch rewrites Use 'git fetch' followed by 'git reset' to update the source tree. This is better than 'git pull' because it can handle a rewritten upstream branch and does not leave local modifications. After fetch, parse FETCH_HEAD to find the merge head that 'git pull' would choose to track the upstream branch. Then reset to the selected head. In the normal fast-forward case the behavior remains unchanged. However, now local modifications and commits will be erased, and upstream rewrites are handled smoothly. This ensures that the upstream branch is tested as expected. --- ChangeLog.manual | 1 + Source/CTest/cmCTestGIT.cxx | 53 ++++++++++++++++++++++++++--------- Source/CTest/cmCTestGIT.h | 2 +- Tests/CTestUpdateCommon.cmake | 6 +++- Tests/CTestUpdateGIT.cmake.in | 2 ++ Tests/CTestUpdateGIT.sh.in | 2 +- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/ChangeLog.manual b/ChangeLog.manual index 29162e9ef..b93586025 100644 --- a/ChangeLog.manual +++ b/ChangeLog.manual @@ -15,6 +15,7 @@ Changes since CMake 2.8.1 - CTest: Report failure in Update.xml - CTest: Submit author email in Update.xml - CTest: Teach ctest_update about Git submodules +- CTest: Teach ctest_update to handle Git upstream branch rewrites - Cygwin: Export all symbols with ENABLE_EXPORTS (#10122) - Do not list file names during 'cmake -E tar xz' - Documentation: Comply with "XHTML 1.0 Strict" diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 5972d39bc..6c3631c90 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -85,16 +85,14 @@ void cmCTestGIT::NoteNewRevision() } //---------------------------------------------------------------------------- -bool cmCTestGIT::UpdateByPull() +bool cmCTestGIT::UpdateByFetchAndReset() { const char* git = this->CommandLineTool.c_str(); - // Use "git pull" to update the working tree. - std::vector git_pull; - git_pull.push_back(git); - git_pull.push_back("pull"); - - // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY) + // Use "git fetch" to get remote commits. + std::vector git_fetch; + git_fetch.push_back(git); + git_fetch.push_back("fetch"); // Add user-specified update options. std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions"); @@ -106,15 +104,44 @@ bool cmCTestGIT::UpdateByPull() for(std::vector::const_iterator ai = args.begin(); ai != args.end(); ++ai) { - git_pull.push_back(ai->c_str()); + git_fetch.push_back(ai->c_str()); } // Sentinel argument. - git_pull.push_back(0); + git_fetch.push_back(0); - OutputLogger out(this->Log, "pull-out> "); - OutputLogger err(this->Log, "pull-err> "); - return this->RunUpdateCommand(&git_pull[0], &out, &err); + // Fetch upstream refs. + OutputLogger fetch_out(this->Log, "fetch-out> "); + OutputLogger fetch_err(this->Log, "fetch-err> "); + if(!this->RunUpdateCommand(&git_fetch[0], &fetch_out, &fetch_err)) + { + return false; + } + + // Identify the merge head that would be used by "git pull". + std::string sha1; + { + std::string fetch_head = this->SourceDirectory + "/.git/FETCH_HEAD"; + std::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary); + std::string line; + while(sha1.empty() && cmSystemTools::GetLineFromStream(fin, line)) + { + if(line.find("\tnot-for-merge\t") == line.npos) + { + std::string::size_type pos = line.find('\t'); + if(pos != line.npos) + { + sha1 = line.substr(0, pos); + } + } + } + } + + // Reset the local branch to point at that tracked from upstream. + char const* git_reset[] = {git, "reset", "--hard", sha1.c_str(), 0}; + OutputLogger reset_out(this->Log, "reset-out> "); + OutputLogger reset_err(this->Log, "reset-err> "); + return this->RunChild(&git_reset[0], &reset_out, &reset_err); } //---------------------------------------------------------------------------- @@ -143,7 +170,7 @@ bool cmCTestGIT::UpdateInternal() { return this->UpdateByCustom(custom); } - return this->UpdateByPull(); + return this->UpdateByFetchAndReset(); } //---------------------------------------------------------------------------- diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h index bdb2c6269..d8681fe4f 100644 --- a/Source/CTest/cmCTestGIT.h +++ b/Source/CTest/cmCTestGIT.h @@ -32,7 +32,7 @@ private: virtual void NoteNewRevision(); virtual bool UpdateImpl(); - bool UpdateByPull(); + bool UpdateByFetchAndReset(); bool UpdateByCustom(std::string const& custom); bool UpdateInternal(); diff --git a/Tests/CTestUpdateCommon.cmake b/Tests/CTestUpdateCommon.cmake index c62505c8f..a52cb148d 100644 --- a/Tests/CTestUpdateCommon.cmake +++ b/Tests/CTestUpdateCommon.cmake @@ -191,13 +191,17 @@ function(run_dashboard_command_line bin_dir) # Verify the updates reported by CTest. list(APPEND UPDATE_MAYBE Updated{subdir}) + set(_modified Modified{CTestConfig.cmake}) + if(UPDATE_NO_MODIFIED) + set(_modified "") + endif() check_updates(${bin_dir} Updated{foo.txt} Updated{bar.txt} Updated{zot.txt} Updated{subdir/foo.txt} Updated{subdir/bar.txt} - Modified{CTestConfig.cmake} + ${_modified} ) endfunction(run_dashboard_command_line) diff --git a/Tests/CTestUpdateGIT.cmake.in b/Tests/CTestUpdateGIT.cmake.in index 95461bb96..4ac1b3177 100644 --- a/Tests/CTestUpdateGIT.cmake.in +++ b/Tests/CTestUpdateGIT.cmake.in @@ -227,7 +227,9 @@ UpdateCommand: ${GIT} ") # Run the dashboard command line interface. +set(UPDATE_NO_MODIFIED 1) run_dashboard_command_line(user-binary) +set(UPDATE_NO_MODIFIED 0) rewind_source(user-source) modify_content(user-source) diff --git a/Tests/CTestUpdateGIT.sh.in b/Tests/CTestUpdateGIT.sh.in index 4761d3293..e7586d6bf 100755 --- a/Tests/CTestUpdateGIT.sh.in +++ b/Tests/CTestUpdateGIT.sh.in @@ -1,5 +1,5 @@ #!/bin/sh -if test "x$1" = "xpull"; then +if test "x$1" = "xpull" -o "x$1" = "xreset"; then "@GIT@" "$@" && sleep 1 && touch foo.txt else exec "@GIT@" "$@"