implement basic node management skeleton (which does not really manage nodes, just...
authorAtsushi Eno <atsushieno@veritas-vos-liberabit.com>
Tue, 19 Nov 2013 16:13:18 +0000 (01:13 +0900)
committerAtsushi Eno <atsushieno@veritas-vos-liberabit.com>
Tue, 3 Dec 2013 07:51:43 +0000 (16:51 +0900)
mcs/class/Microsoft.Build/Microsoft.Build.Execution/BuildManager.cs
mcs/class/Microsoft.Build/Microsoft.Build.Execution/BuildParameters.cs
mcs/class/Microsoft.Build/Microsoft.Build.Execution/BuildSubmission.cs
mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildEngine4.cs
mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs [new file with mode: 0644]
mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildTaskFactory.cs
mcs/class/Microsoft.Build/Microsoft.Build.dll.sources
mcs/class/Microsoft.Build/Test/Microsoft.Build.Execution/BuildManagerTest.cs
mcs/class/Microsoft.Build/Test/Microsoft.Build.Execution/BuildParametersTest.cs
mcs/class/Microsoft.Build/Test/Microsoft.Build.Execution/BuildSubmissionTest.cs

index 9e89f3c550b4ea8503dcd21c2ba8f60c1c639c3f..9b5940680180df3e724ce538d25778f3ba88b653 100644 (file)
@@ -28,7 +28,6 @@
 using Microsoft.Build.Evaluation;
 using System;
 using System.Collections.Generic;
-using System.Threading.Tasks;
 using System.Threading;
 using Microsoft.Build.Internal;
 using System.Linq;
@@ -37,8 +36,15 @@ namespace Microsoft.Build.Execution
 {
        public class BuildManager
        {
+               static BuildManager default_manager = new BuildManager ();
+
+               public static BuildManager DefaultBuildManager {
+                       get { return default_manager; }
+               }
+               
                public BuildManager ()
                {
+                       build_node_manager = new BuildNodeManager (this);
                }
 
                public BuildManager (string hostName)
@@ -48,18 +54,20 @@ namespace Microsoft.Build.Execution
                
                public void Dispose ()
                {
+                       WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
+                       BuildNodeManager.Stop ();
                }
 
                ~BuildManager ()
                {
-                       // maybe HostServices related cleanup is expected.
+                       // maybe processes created by out-of-process nodes should be signaled.
+                       BuildNodeManager.Stop ();
                }
 
-               readonly TaskFactory<BuildResult> task_factory = new TaskFactory<BuildResult> ();
-               List<BuildSubmission> submissions = new List<BuildSubmission> ();
+               readonly List<BuildSubmission> submissions = new List<BuildSubmission> ();
                
                BuildParameters ongoing_build_parameters;
-                               
+               
                internal BuildParameters OngoingBuildParameters {
                        get { return ongoing_build_parameters; }
                }
@@ -68,9 +76,7 @@ namespace Microsoft.Build.Execution
                {
                        if (ongoing_build_parameters != null)
                                throw new InvalidOperationException ("There is already ongoing build");
-                       ongoing_build_parameters = parameters;
-                       
-                       // FIXME: apply build parameters to this build manager instance.
+                       ongoing_build_parameters = parameters.Clone ();
                }
 
                public BuildResult Build (BuildParameters parameters, BuildRequestData requestData)
@@ -88,8 +94,14 @@ namespace Microsoft.Build.Execution
                
                public void CancelAllSubmissions ()
                {
-                       foreach (var sub in submissions)
-                               sub.Cancel ();
+                       foreach (var sub in submissions) {
+                               try {
+                                       if (!sub.IsCompleted)
+                                               sub.Cancel ();
+                               } catch (InvalidOperationException) {
+                                       // some submissions could be already done during this iteration. Ignore that.
+                               }
+                       }
                        submissions.Clear ();
                }
 
@@ -97,8 +109,12 @@ namespace Microsoft.Build.Execution
                {
                        if (ongoing_build_parameters == null)
                                throw new InvalidOperationException ("Build has not started");
+//Console.Error.WriteLine ("{0} EndBuild waiting for subs: " + submissions.Count, GetHashCode ());
                        if (submissions.Count > 0)
                                WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
+//Console.Error.WriteLine ("{0} EndBuild waiting for NodeManager", GetHashCode ());
+                       BuildNodeManager.Stop ();
+//Console.Error.WriteLine ("{0} EndBuild done", GetHashCode ());
                        ongoing_build_parameters = null;
                }
                
@@ -136,7 +152,11 @@ namespace Microsoft.Build.Execution
 
                public void ResetCaches ()
                {
-                       throw new NotImplementedException ();
+                       if (OngoingBuildParameters != null)
+                               throw new InvalidOperationException ("Cannot reset caches while builds are in progress.");
+                       
+                       build_node_manager.ResetCaches ();
+                       build_task_factory.ResetCaches ();
                }
 
                BuildTaskFactory build_task_factory = new BuildTaskFactory ();
@@ -144,16 +164,11 @@ namespace Microsoft.Build.Execution
                internal BuildTaskFactory BuildTaskFactory {
                        get { return build_task_factory; }      
                }
-
-               internal TaskFactory<BuildResult> ThreadTaskFactory {
-                       get { return task_factory; }
-               }
                
-               static BuildManager default_manager = new BuildManager ();
-
-               public static BuildManager DefaultBuildManager {
-                       get { return default_manager; }
+               BuildNodeManager build_node_manager;
+               
+               internal BuildNodeManager BuildNodeManager {
+                       get { return build_node_manager; }
                }
        }
 }
-
index 05b94440e41e6fcd6cbb5c6d1cb0ca5d602b0c0c..571a05dce29ffd11ccd499f70c1558d6c1cd6da7 100644 (file)
@@ -34,6 +34,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Threading;
+using System.Collections;
 
 namespace Microsoft.Build.Execution
 {
@@ -49,14 +50,22 @@ namespace Microsoft.Build.Execution
                        if (projectCollection == null)
                                throw new ArgumentNullException ("projectCollection");
                        projects = projectCollection;
+                       
+                       EnableNodeReuse = true;
+                       Culture = CultureInfo.CurrentCulture;
+                       UICulture = CultureInfo.CurrentUICulture;
 
                        // these properties are copied, while some members (such as Loggers) are not.
                        this.DefaultToolsVersion = projectCollection.DefaultToolsVersion;
                        this.ToolsetDefinitionLocations = projectCollection.ToolsetLocations;
                        this.GlobalProperties = projectCollection.GlobalProperties;
+                       environment_properties = new Dictionary<string,string> ();
+                       foreach (DictionaryEntry p in Environment.GetEnvironmentVariables ())
+                               environment_properties [(string) p.Key] = (string) p.Value;
                }
 
                readonly ProjectCollection projects;
+               Dictionary<string,string> environment_properties;
                
                internal ProjectCollection ProjectCollection {
                        get { return projects; }
@@ -65,9 +74,10 @@ namespace Microsoft.Build.Execution
                public BuildParameters Clone ()
                {
                        var ret = (BuildParameters) MemberwiseClone ();
-                       ret.ForwardingLoggers = ret.ForwardingLoggers.ToArray ();
-                       ret.GlobalProperties = ret.GlobalProperties.ToDictionary (p => p.Key, p => p.Value);
-                       ret.Loggers = ret.Loggers == null ? null : ret.Loggers.ToArray ();
+                       ret.ForwardingLoggers = ForwardingLoggers == null ? null : ForwardingLoggers.ToArray ();
+                       ret.GlobalProperties = GlobalProperties == null ? null : GlobalProperties.ToDictionary (p => p.Key, p => p.Value);
+                       ret.Loggers = Loggers == null ? null : new List<ILogger> (Loggers);
+                       ret.environment_properties = new Dictionary<string, string> (environment_properties);
                        return ret;
                }
 
@@ -89,12 +99,11 @@ namespace Microsoft.Build.Execution
                [MonoTODO]
                public bool DetailedSummary { get; set; }
 
-               [MonoTODO]
                public bool EnableNodeReuse { get; set; }
 
                [MonoTODO]
                public IDictionary<string, string> EnvironmentProperties {
-                       get { throw new NotImplementedException (); }
+                       get { return environment_properties; }
                }
 
                [MonoTODO]
@@ -103,7 +112,6 @@ namespace Microsoft.Build.Execution
                [MonoTODO]
                public IDictionary<string, string> GlobalProperties { get; set; }
 
-               [MonoTODO]
                public HostServices HostServices { get; set; }
 
                [MonoTODO]
index 148951805f817703029b93e345e6852a2c18d838..3af4273ead04c772123e84c2610ad3d9f9794aaa 100644 (file)
@@ -50,7 +50,7 @@ namespace Microsoft.Build.Execution
                BuildRequestData request;
                BuildSubmissionCompleteCallback callback;
                bool is_started, is_completed, is_canceled;
-               ManualResetEvent wait_handle = new ManualResetEvent (false);
+               ManualResetEvent wait_handle = new ManualResetEvent (true);
 
                public object AsyncContext { get; private set; }
                public BuildManager BuildManager { get; private set; }
@@ -60,11 +60,7 @@ namespace Microsoft.Build.Execution
                }
                public int SubmissionId { get; private set; }
                public WaitHandle WaitHandle {
-                       get {
-                               if (!is_started)
-                                       throw new InvalidOperationException ("Build has not started yet");
-                               return wait_handle;
-                       }
+                       get { return wait_handle; }
                }
                
                internal BuildRequestData BuildRequest {
@@ -80,10 +76,16 @@ namespace Microsoft.Build.Execution
 
                public BuildResult Execute ()
                {
-                       var engine = new BuildEngine4 (this);
-                       string toolsVersion = request.ExplicitlySpecifiedToolsVersion ?? request.ProjectInstance.ToolsVersion ?? BuildManager.OngoingBuildParameters.DefaultToolsVersion;
-                       var outputs = new Dictionary<string,string> ();
-                       BuildResult = engine.BuildProject (() => is_canceled, request.ProjectInstance, request.TargetNames, BuildManager.OngoingBuildParameters.GlobalProperties, outputs, toolsVersion);
+                       BuildResult = new BuildResult () { SubmissionId = SubmissionId };
+                       try {
+                               var engine = new BuildEngine4 (this);
+                               string toolsVersion = request.ExplicitlySpecifiedToolsVersion ?? request.ProjectInstance.ToolsVersion ?? BuildManager.OngoingBuildParameters.DefaultToolsVersion;
+                               var outputs = new Dictionary<string,string> ();
+                               engine.BuildProject (() => is_canceled, BuildResult, request.ProjectInstance, request.TargetNames, BuildManager.OngoingBuildParameters.GlobalProperties, outputs, toolsVersion);
+                       } catch (Exception ex) {
+                               BuildResult.Exception = ex;
+                               BuildResult.OverallResult = BuildResultCode.Failure;
+                       }
                        wait_handle.Set ();
                        if (callback != null)
                                callback (this);
@@ -99,8 +101,9 @@ namespace Microsoft.Build.Execution
                        is_started = true;
                        this.AsyncContext = context;
                        this.callback = callback;
+                       wait_handle.Reset ();
                        
-                       BuildManager.ThreadTaskFactory.StartNew (Execute);
+                       BuildManager.BuildNodeManager.Enqueue (this);
                }
        }
 }
index e58f018f47d6c7be326b7029ccf616808c6e4d1e..0d392f6d1157a40b22e6b40cff2bd4325974ab21 100644 (file)
@@ -46,7 +46,7 @@ namespace Microsoft.Build.Internal
                }
 
                BuildSubmission submission;
-               ProjectInstance current_project;
+               ProjectInstance project;
                ProjectTaskInstance current_task;
                EventSource event_source;
                
@@ -66,11 +66,11 @@ namespace Microsoft.Build.Internal
                // (which is most likely derived from AppDomainIsolatedBuildTask) that marks a task to run
                // in separate AppDomain.
                //
-               public BuildResult BuildProject (Func<bool> checkCancel, ProjectInstance project, IEnumerable<string> targetNames, IDictionary<string,string> globalProperties, IDictionary<string,string> targetOutputs, string toolsVersion)
+               public void BuildProject (Func<bool> checkCancel, BuildResult result, ProjectInstance project, IEnumerable<string> targetNames, IDictionary<string,string> globalProperties, IDictionary<string,string> targetOutputs, string toolsVersion)
                {
-                       var result = new BuildResult () { SubmissionId = submission.SubmissionId };
                        var request = submission.BuildRequest;
                        var parameters = submission.BuildManager.OngoingBuildParameters;
+                       this.project = project;
                        
                        // null targets -> success. empty targets -> success(!)
                        if (request.TargetNames == null)
@@ -86,23 +86,23 @@ namespace Microsoft.Build.Internal
                                                result.AddResultsForTarget (targetName, new TargetResult (new ITaskItem [0], TargetResultCode.Failure));
                                        else {
                                                foreach (var c in target.Children.OfType<ProjectPropertyGroupTaskInstance> ()) {
-                                                       if (!current_project.EvaluateCondition (c.Condition))
+                                                       if (!project.EvaluateCondition (c.Condition))
                                                                continue;
                                                        throw new NotImplementedException ();
                                                }
                                                foreach (var c in target.Children.OfType<ProjectItemGroupTaskInstance> ()) {
-                                                       if (!current_project.EvaluateCondition (c.Condition))
+                                                       if (!project.EvaluateCondition (c.Condition))
                                                                continue;
                                                        throw new NotImplementedException ();
                                                }
                                                foreach (var c in target.Children.OfType<ProjectOnErrorInstance> ()) {
-                                                       if (!current_project.EvaluateCondition (c.Condition))
+                                                       if (!project.EvaluateCondition (c.Condition))
                                                                continue;
                                                        throw new NotImplementedException ();
                                                }
                                                foreach (var c in target.Children.OfType<ProjectTaskInstance> ()) {
                                                        var host = request.HostServices == null ? null : request.HostServices.GetHostObject (request.ProjectFullPath, targetName, c.Name);
-                                                       if (!current_project.EvaluateCondition (c.Condition))
+                                                       if (!project.EvaluateCondition (c.Condition))
                                                                continue;
                                                        current_task = c;
                                                        // MSBuildArchitecture and MSBuildRuntime attributes cannot be suppored.
@@ -115,7 +115,6 @@ namespace Microsoft.Build.Internal
                                // FIXME: check .NET behavior, whether cancellation always results in failure.
                                result.OverallResult = checkCancel () ? BuildResultCode.Failure : result.ResultsByTarget.Select (p => p.Value).Any (r => r.ResultCode == TargetResultCode.Failure) ? BuildResultCode.Failure : BuildResultCode.Success;
                        }
-                       return result;
                }
                
                #region IBuildEngine4 implementation
@@ -183,12 +182,13 @@ namespace Microsoft.Build.Internal
 
                public bool BuildProjectFile (string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs, string toolsVersion)
                {
-                       var project = GetProjectInstance (projectFileName, toolsVersion);
+                       var proj = GetProjectInstance (projectFileName, toolsVersion);
                        var globalPropertiesThatMakeSense = new Dictionary<string,string> ();
                        foreach (DictionaryEntry p in globalProperties)
                                globalPropertiesThatMakeSense [(string) p.Key] = (string) p.Value;
+                       var result = new BuildResult ();
                        var outputs = new Dictionary<string, string> ();
-                       var result = BuildProject (() => false, project, targetNames, globalPropertiesThatMakeSense, outputs, toolsVersion);
+                       BuildProject (() => false, result, proj, targetNames, globalPropertiesThatMakeSense, outputs, toolsVersion);
                        foreach (var p in outputs)
                                targetOutputs [p.Key] = p.Value;
                        return result.OverallResult == BuildResultCode.Success;
diff --git a/mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs b/mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs
new file mode 100644 (file)
index 0000000..dbfa77d
--- /dev/null
@@ -0,0 +1,174 @@
+//
+// BuildEngine4.cs
+//
+// Author:
+//   Atsushi Enomoto (atsushi@xamarin.com)
+//
+// Copyright (C) 2013 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Build.Execution;
+using Microsoft.Build.Framework;
+using System.Threading.Tasks;
+using System.Threading;
+
+namespace Microsoft.Build.Internal
+{
+       class BuildNodeManager
+       {
+               public BuildNodeManager (BuildManager buildManager)
+               {
+                       BuildManager = buildManager;
+                       task_factory.StartNew (RunLoop);
+               }
+               
+               public BuildManager BuildManager { get; private set; }
+               
+               List<BuildNode> in_proc_nodes = new List<BuildNode> ();
+               List<BuildNode> out_proc_nodes = new List<BuildNode> ();
+               AutoResetEvent queue_wait_handle = new AutoResetEvent (false);
+               Queue<BuildSubmission> queued_builds = new Queue<BuildSubmission> ();
+               Dictionary<BuildSubmission,Task> ongoing_builds = new Dictionary<BuildSubmission, Task> ();
+               bool run_loop = true;
+
+               readonly TaskFactory task_factory = new TaskFactory ();
+               internal TaskFactory ThreadTaskFactory {
+                       get { return task_factory; }
+               }
+               
+               void RunLoop ()
+               {
+                       while (run_loop) {
+                               if (queued_builds.Count == 0) {
+//Console.Error.WriteLine ("!!!! {0} waiting for build queue...", BuildManager.GetHashCode ());
+                                       queue_wait_handle.WaitOne ();
+                               }
+                               if (!run_loop)
+                                       break;
+                               if (!queued_builds.Any ())
+                                       continue;
+                               var build = queued_builds.Dequeue ();
+                               Execute (build);
+                       }
+               }
+
+               public void Stop ()
+               {
+                       run_loop = false;
+                       queue_wait_handle.Set ();
+               }
+
+               public void ResetCaches ()
+               {
+                       in_proc_nodes.Clear ();
+                       out_proc_nodes.Clear ();
+               }
+               
+               public void Enqueue (BuildSubmission build)
+               {
+                       queued_builds.Enqueue (build);
+                       queue_wait_handle.Set ();
+               }
+               
+               void Execute (BuildSubmission build)
+               {
+//Console.Error.WriteLine ("!!!! {0} BuildNodeManager.Execute", BuildManager.GetHashCode ());
+                       var node = TakeNode (build);
+                       ongoing_builds [build] = task_factory.StartNew (node.Execute);
+               }
+               
+               // FIXME: take max nodes into account here, and get throttling working.
+               BuildNode TakeNode (BuildSubmission build)
+               {
+                       var host = BuildManager.OngoingBuildParameters.HostServices;
+                       NodeAffinity affinity;
+                       if (host == null)
+                               affinity = NodeAffinity.Any;
+                       else
+                               affinity = host.GetNodeAffinity (build.BuildRequest.ProjectFullPath);
+                       BuildNode n = GetReusableNode (affinity);
+                       if (n != null)
+                               n.Assign (build);
+                       else {
+                               n = new BuildNode (this, affinity == NodeAffinity.Any ? NodeAffinity.InProc : affinity);
+                               n.Assign (build);
+                               if (n.Affinity == NodeAffinity.InProc)
+                                       in_proc_nodes.Add (n);
+                               else
+                                       out_proc_nodes.Add (n);
+                       }
+                       return n;
+               }
+               
+               BuildNode GetReusableNode (NodeAffinity affinity)
+               {
+                       if (!BuildManager.OngoingBuildParameters.EnableNodeReuse)
+                               return null;
+                       
+                       if (affinity != NodeAffinity.OutOfProc)
+                               foreach (var n in in_proc_nodes)
+                                       if (n.IsAvailable && (n.Affinity & affinity) != 0)
+                                               return n;
+                       if (affinity != NodeAffinity.InProc)
+                               foreach (var n in out_proc_nodes)
+                                       if (n.IsAvailable && (n.Affinity & affinity) != 0)
+                                               return n;
+                       return null;
+               }
+       
+               internal class BuildNode
+               {
+                       static Random rnd = new Random ();
+                       
+                       public BuildNode (BuildNodeManager manager, NodeAffinity affinity)
+                       {
+                               Manager = manager;
+                               Affinity = affinity;
+                               Id = rnd.Next ();
+                       }
+                       
+                       public bool IsAvailable { get; private set; }
+                       public int Id { get; private set; }
+                       public BuildNodeManager Manager { get; set; }
+                       public NodeAffinity Affinity { get; private set; }
+                       public BuildSubmission Build { get; private set; }
+                       
+                       public void Assign (BuildSubmission build)
+                       {
+                               IsAvailable = false;
+                               Build = build;
+                       }
+                       
+                       public void Execute ()
+                       {
+                               // FIXME: depending on NodeAffinity, build it through another MSBuild process.
+                               if (Affinity == NodeAffinity.OutOfProc)
+                                       throw new NotImplementedException ();
+//Console.Error.WriteLine ("!!!! {0} BuildSubmission.Execute start", Manager.BuildManager.GetHashCode ());
+                               Build.Execute ();
+//Console.Error.WriteLine ("!!!! {0} BuildSubmission.Execute done", Manager.BuildManager.GetHashCode ());
+                       }
+               }
+       }
+}
index 54ae98feb31de5fb3699f438ccff71d3282eed03..502ed83f751b2a93a40aba23ad056bb3aaa0b543 100644 (file)
@@ -41,6 +41,12 @@ namespace Microsoft.Build.Internal
                List<Assembly> assemblies = new List<Assembly> ();
                List<ITaskFactory> task_factories = new List<ITaskFactory> ();
                
+               public void ResetCaches ()
+               {
+                       assemblies.Clear ();
+                       task_factories.Clear ();
+               }
+               
                public ITask GetTask (string name)
                {
                        throw new NotImplementedException ();
index 773dac4e352e8f29f15492e525f5693d0caa8aed..9b83638c9817a7c263451f214ad73a1354a5e103 100644 (file)
@@ -86,6 +86,7 @@ Microsoft.Build.Execution/ProjectTargetInstanceChild.cs
 Microsoft.Build.Execution/TargetResult.cs                           
 Microsoft.Build.Execution/TargetResultCode.cs
 Microsoft.Build.Internal/BuildEngine4.cs
+Microsoft.Build.Internal/BuildNodeManager.cs
 Microsoft.Build.Internal/BuildTaskFactory.cs
 Microsoft.Build.Internal/CollectionFromEnumerable.cs
 Microsoft.Build.Internal/ExpressionConstructs.cs
index de44cb9810d9d97c12b964e114ec0d26ee2ba16a..5730c93c9ad10b0540312e05b83f3094559c8007 100644 (file)
@@ -32,6 +32,8 @@ using Microsoft.Build.Construction;
 using Microsoft.Build.Evaluation;
 using Microsoft.Build.Execution;
 using NUnit.Framework;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace MonoTests.Microsoft.Build.Execution
 {
@@ -90,6 +92,57 @@ namespace MonoTests.Microsoft.Build.Execution
                        var proj = new ProjectInstance (root);
             new BuildManager ().PendBuildRequest (new BuildRequestData (proj, new string [0]));
                }
+               
+               [Test]
+               [ExpectedException (typeof (InvalidOperationException))]
+               public void ResetCachesDuringBuildIsInvalid ()
+               {
+                       string project_xml = @"<Project DefaultTargets='Wait1Sec' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
+  <Target Name='Wait1Sec'>
+    <Exec Command='ping 10.1.1.1 -n 1 -w 1' />
+  </Target>
+</Project>";
+                       var xml = XmlReader.Create (new StringReader (project_xml));
+                       var root = ProjectRootElement.Create (xml);
+                       var proj = new ProjectInstance (root);
+                       var bm = new BuildManager ();
+                       bm.BeginBuild (new BuildParameters ());
+                       var sub = bm.PendBuildRequest (new BuildRequestData (proj, new string [] { "Wait5Sec" }));
+                       sub.ExecuteAsync (delegate {}, null);
+                       try {
+                               bm.ResetCaches ();
+                       } finally {
+                               bm.EndBuild (); // yes, it should work even after invalid ResetCaches call... at least on .NET it does.
+                       }
+               }
+               
+               [Test]
+               public void BasicManualParallelBuilds ()
+               {
+                       string project_xml = @"<Project DefaultTargets='Wait1Sec' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
+  <Target Name='Wait1Sec'>
+    <Exec Command='ping 10.1.1.1 -n 1 -w 1' />
+  </Target>
+</Project>";
+                       var xml = XmlReader.Create (new StringReader (project_xml));
+                       var root = ProjectRootElement.Create (xml);
+                       var proj = new ProjectInstance (root);
+                       var bm = new BuildManager ();
+                       bm.BeginBuild (new BuildParameters ());
+                       DateTime waitDone = DateTime.MinValue;
+                       DateTime beforeExec = DateTime.Now;
+                       var l = new List<BuildSubmission> ();
+                       for (int i = 0; i < 10; i++) {
+                               var sub = bm.PendBuildRequest (new BuildRequestData (proj, new string [] { "Wait5Sec" }));
+                               l.Add (sub);
+                               sub.ExecuteAsync (delegate { waitDone = DateTime.Now; }, null);
+                       }
+                       bm.EndBuild ();
+                       Assert.IsTrue (l.All (s => s.BuildResult.OverallResult == BuildResultCode.Success), "#1");
+                       DateTime endBuildDone = DateTime.Now;
+                       Assert.IsTrue (endBuildDone - beforeExec >= TimeSpan.FromSeconds (1), "#2");
+                       Assert.IsTrue (endBuildDone > waitDone, "#3");
+               }
        }
 }
 
index ded98f9f8321bbd8d6e4f04b2d908491378b9214..47cd5f9007e5419990059e0b79ee8e564207cf47 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 using System;
+using System.Globalization;
 using System.IO;
 using System.Linq;
-using System.Xml;
-using Microsoft.Build.Construction;
 using Microsoft.Build.Evaluation;
 using Microsoft.Build.Execution;
 using NUnit.Framework;
@@ -54,6 +53,14 @@ namespace MonoTests.Microsoft.Build.Execution
                        // They are NOT equal, because ProjectCollection seems to be different.
                        Assert.AreNotEqual (ProjectCollection.GlobalProjectCollection.Toolsets.First (t => t.ToolsVersion == "2.0"), ts, "#2");                 
                }
+               
+               [Test]
+               public void PropertiesDefault ()
+               {
+                       var bp = new BuildParameters ();
+                       Assert.IsTrue (bp.EnableNodeReuse, "#1");
+                       Assert.IsTrue (bp.EnvironmentProperties.Count > 0, "#2");
+                       Assert.AreEqual (CultureInfo.CurrentCulture, bp.Culture, "#3");
+               }
        }
 }
-
index 8b753e5f753ed75ac8f1eb38c6d01c527c68a19d..09659e27a356a7e89912dde12b3103c107447a82 100644 (file)
@@ -81,7 +81,7 @@ namespace MonoTests.Microsoft.Build.Execution
                {
                        string project_xml = @"<Project DefaultTargets='Wait1Sec' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
   <Target Name='Wait1Sec'>
-    <Exec Command='ping 10.1.1.1 -n 1 -w 1000' />
+    <Exec Command='ping 10.1.1.1 -n 1 -w 1' />
   </Target>
 </Project>";
                        var xml = XmlReader.Create (new StringReader (project_xml));
@@ -91,14 +91,10 @@ namespace MonoTests.Microsoft.Build.Execution
                        bm.BeginBuild (new BuildParameters ());
                        DateTime waitDone = DateTime.MinValue;
                        DateTime beforeExec = DateTime.Now;
-                       var l = new List<BuildSubmission> ();
-                       for (int i = 0; i < 10; i++) {
-                               var sub = bm.PendBuildRequest (new BuildRequestData (proj, new string [] { "Wait5Sec" }));
-                               l.Add (sub);
-                               sub.ExecuteAsync (delegate { waitDone = DateTime.Now; }, null);
-                       }
+                       var sub = bm.PendBuildRequest (new BuildRequestData (proj, new string [] { "Wait5Sec" }));
+                       sub.ExecuteAsync (delegate { waitDone = DateTime.Now; }, null);
                        bm.EndBuild ();
-                       Assert.IsTrue (l.All (s => s.BuildResult.OverallResult == BuildResultCode.Success), "#1");
+                       Assert.IsTrue (sub.BuildResult.OverallResult == BuildResultCode.Success, "#1");
                        DateTime endBuildDone = DateTime.Now;
                        Assert.IsTrue (endBuildDone - beforeExec >= TimeSpan.FromSeconds (1), "#2");
                        Assert.IsTrue (endBuildDone > waitDone, "#3");