Merge pull request #70 from neonichu/fix-command-task-cancellation

Call `taskIsComplete()` on CommandTask cancellation
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 89fbc9a..3f009fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -199,6 +199,10 @@
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
 endif ()
 
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLLVM_ON_WIN32")
+endif()
+
 # On BSD and Linux, always build with PIC.
 if(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
diff --git a/lib/BuildSystem/BuildSystem.cpp b/lib/BuildSystem/BuildSystem.cpp
index 2a53e5e..ba50b33 100644
--- a/lib/BuildSystem/BuildSystem.cpp
+++ b/lib/BuildSystem/BuildSystem.cpp
@@ -1505,6 +1505,8 @@
     if (value.isFailedCommand() || value.isPropagatedFailureCommand() ||
         value.isCancelledCommand())
       return BuildValue::makeFailedInput();
+    if (value.isSkippedCommand())
+      return BuildValue::makeSkippedCommand();
 
     // Otherwise, we should have a successful command -- return the actual
     // result for the output.
@@ -1744,6 +1746,8 @@
     if (value.isFailedCommand() || value.isPropagatedFailureCommand() ||
         value.isCancelledCommand())
       return BuildValue::makeFailedInput();
+    if (value.isSkippedCommand())
+      return BuildValue::makeSkippedCommand();
 
     // Otherwise, we should have a successful command -- return the actual
     // result for the output.
diff --git a/unittests/BuildSystem/BuildSystemFrontendTest.cpp b/unittests/BuildSystem/BuildSystemFrontendTest.cpp
index a0426bc..fe39665 100644
--- a/unittests/BuildSystem/BuildSystemFrontendTest.cpp
+++ b/unittests/BuildSystem/BuildSystemFrontendTest.cpp
@@ -384,4 +384,93 @@
 
 }
 
+// Built-in commands don't process skipped inputs the same way as external
+// commands (for now). Add explicit tests to make sure they behave as expected.
+TEST_F(BuildSystemFrontendTest, commandSkipping_NonExternalCommands_mkdir) {
+  writeBuildFile(R"END(
+client:
+    name: client
+
+targets:
+    "": ["2"]
+
+commands:
+    1:
+        tool: mkdir
+        outputs: ["1"]
+    2:
+        tool: mkdir
+        inputs: ["1"]
+        outputs: ["2"]
+)END");
+
+  TestBuildSystemFrontendDelegate delegate(sourceMgr, invocation, *fs);
+  delegate.commandsToSkip.insert("1");
+  
+  BuildSystemFrontend frontend(delegate, invocation);
+  ASSERT_TRUE(frontend.build(""));
+
+  ASSERT_TRUE(delegate.checkTrace(R"END(
+commandPreparing: 2
+commandPreparing: 1
+shouldCommandStart: 1
+commandFinished: 1
+shouldCommandStart: 2
+commandStarted: 2
+commandFinished: 2
+)END"));
+}
+
+// Built-in commands don't process skipped inputs the same way as external
+// commands (for now). Add explicit tests to make sure they behave as expected.
+TEST_F(BuildSystemFrontendTest, commandSkipping_NonExternalCommands_symlink) {
+  writeBuildFile(R"END(
+client:
+    name: client
+
+targets:
+    "": ["3"]
+
+commands:
+    1:
+        tool: symlink
+        outputs: ["1"]
+        contents: "x"
+    2:
+        tool: symlink
+        inputs: ["1"]
+        outputs: ["2"]
+        contents: "y"
+    3:
+        tool: shell
+        inputs: ["2"]
+        outputs: ["3"]
+        args: rm 2
+)END");
+  // We need to delete the symlink ourselves, because llvm's remove()
+  // currently refuses to delete symlinks.
+
+  TestBuildSystemFrontendDelegate delegate(sourceMgr, invocation, *fs);
+  delegate.commandsToSkip.insert("1");
+  
+  BuildSystemFrontend frontend(delegate, invocation);
+  ASSERT_TRUE(frontend.build(""));
+
+  ASSERT_TRUE(delegate.checkTrace(R"END(
+commandPreparing: 3
+commandPreparing: 2
+commandPreparing: 1
+shouldCommandStart: 1
+commandFinished: 1
+shouldCommandStart: 2
+commandStarted: 2
+commandFinished: 2
+shouldCommandStart: 3
+commandStarted: 3
+commandProcessStarted: 3
+commandProcessFinished: 3: 0
+commandFinished: 3
+)END"));
+}
+
 }