[xbuild] Handle a repeat build of a target, when building through ..
authorAnkit Jain <ankit.jain@xamarin.com>
Wed, 16 Nov 2016 22:42:12 +0000 (17:42 -0500)
committerAnkit Jain <ankit.jain@xamarin.com>
Wed, 16 Nov 2016 22:59:12 +0000 (17:59 -0500)
.. `Project.Build(..)`. For example, in:

```
<MSBuild Projects="bar.proj" Targets="foo;foo" />
```

The second invocation of `foo`, in the *same* `Project.Build(..)` call,
would get skipped, but BuildTarget assumed that no previous `outputs`
entry existed in the `targetOutputs` dictionary.

System.Exception: MSBuild operation failed ---> System.ArgumentException: Item has already been added. Key in dictionary: 'foo'  Key being added: 'foo'
  at System.Collections.Hashtable.Insert (System.Object key, System.Object nvalue, System.Boolean add) [0x00200] in <94fd79a3b7144c54b4cb162b50fc7761>:0
  at System.Collections.Hashtable.Add (System.Object key, System.Object value) [0x00000] in <94fd79a3b7144c54b4cb162b50fc7761>:0
  at Microsoft.Build.BuildEngine.Project.BuildTarget (System.String target_name, System.Collections.IDictionary targetOutputs) [0x0007e] in <b1524340ac7e4c06b22fac1b2db62c08>:0
  at Microsoft.Build.BuildEngine.Project.BuildInternal (System.String[] targetNames, System.Collections.IDictionary targetOutputs, Microsoft.Build.BuildEngine.BuildSettings buildFlags) [0x00134] in <b1524340ac7e4c06b22fac1b2db62c08>:0
  at Microsoft.Build.BuildEngine.Project.Build (System.String[] targetNames, System.Collections.IDictionary targetOutputs, Microsoft.Build.BuildEngine.BuildSettings buildFlags) [0x0004b] in <b1524340ac7e4c06b22fac1b2db62c08>:0

Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=44549

mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/Project.cs
mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/TargetTest.cs

index 33aad3dea63adebda939e6604a84411ba36560dc..b4ed8562382595c92f99c2b474a5c9ecc4043757 100644 (file)
@@ -374,10 +374,8 @@ namespace Microsoft.Build.BuildEngine {
                                return false;
 
                        ITaskItem[] outputs;
-                       if (ParentEngine.BuiltTargetsOutputByName.TryGetValue (key, out outputs)) {
-                               if (targetOutputs != null)
-                                       targetOutputs.Add (target_name, outputs);
-                       }
+                       if (targetOutputs != null && ParentEngine.BuiltTargetsOutputByName.TryGetValue (key, out outputs))
+                               targetOutputs [target_name] = outputs;
                        return true;
                }
 
index 8f2aa2e7b28daf2b2f4f41ae052bae1b3097e233..d36ae158701c0db1fa8a9243e154b77e399d63bd 100644 (file)
@@ -285,6 +285,51 @@ namespace MonoTests.Microsoft.Build.BuildEngine {
                        t [0].RemoveTask (null);
                }
 
+               [Test]
+               public void TestRunTargetTwice ()
+               {
+                       string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+                       <Target Name=""Foo"">
+                               <Message Text=""Foo ran""/>
+                       </Target>
+                       <Target Name=""Main"">
+                               <MSBuild Projects=""$(MSBuildProjectFile)"" Targets=""Foo;Foo"" />
+                       </Target>
+
+               </Project>";
+
+                       var filepath = Path.GetTempFileName ();
+                       try {
+                               File.WriteAllText (filepath, documentString);
+
+                               var engine = new Engine (Consts.BinPath);
+                               var project = engine.CreateNewProject ();
+                               project.Load (filepath);
+
+                               var logger = new TestMessageLogger ();
+                               engine.RegisterLogger (logger);
+
+                               var result = project.Build ("Main");
+                               if (!result) {
+                                       logger.DumpMessages ();
+                                       Assert.Fail ("Build failed, see the logs");
+                               }
+
+                               Assert.AreEqual(1, logger.NormalMessageCount, "Expected number of messages");
+                               logger.CheckLoggedMessageHead ("Foo ran", "A1");
+
+                               Assert.AreEqual(0, logger.NormalMessageCount, "Extra messages found");
+                               Assert.AreEqual(0, logger.WarningMessageCount, "Extra warning messages found");
+
+                               Assert.AreEqual(2, logger.TargetStarted, "TargetStarted count");
+                               Assert.AreEqual(2, logger.TargetFinished, "TargetFinished count");
+
+                               Assert.IsTrue (result);
+                       } finally {
+                               File.Delete (filepath);
+                       }
+               }
+
                [Test]
                public void TestTargetOutputs1 ()
                {