summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2010-06-08 20:37:04 (GMT)
committerBrad King <brad.king@kitware.com>2010-06-08 20:50:17 (GMT)
commitc3781efb28a35f54ed6306354330734994f2c8b1 (patch)
tree3612ad00fb1dc19bf6e216fc19288c993f222765
parent2eae651acc45c303008d9870a6a4f9da3d8bcf19 (diff)
downloadCMake-c3781efb28a35f54ed6306354330734994f2c8b1.zip
CMake-c3781efb28a35f54ed6306354330734994f2c8b1.tar.gz
CMake-c3781efb28a35f54ed6306354330734994f2c8b1.tar.bz2
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.
-rw-r--r--ChangeLog.manual1
-rw-r--r--Source/CTest/cmCTestGIT.cxx53
-rw-r--r--Source/CTest/cmCTestGIT.h2
-rw-r--r--Tests/CTestUpdateCommon.cmake6
-rw-r--r--Tests/CTestUpdateGIT.cmake.in2
-rwxr-xr-xTests/CTestUpdateGIT.sh.in2
6 files changed, 50 insertions, 16 deletions
diff --git a/ChangeLog.manual b/ChangeLog.manual
index 29162e9..b935860 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 5972d39..6c3631c 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<char const*> 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<char const*> 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<cmStdString>::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);
+
+ // 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);
+ }
+ }
+ }
+ }
- OutputLogger out(this->Log, "pull-out> ");
- OutputLogger err(this->Log, "pull-err> ");
- return this->RunUpdateCommand(&git_pull[0], &out, &err);
+ // 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 bdb2c62..d8681fe 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 c62505c..a52cb14 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 95461bb..4ac1b31 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 4761d32..e7586d6 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@" "$@"