Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Execution / BuildManager.cs
1 // BuildManager.cs
2 //
3 // Author:
4 //   Rolf Bjarne Kvinge (rolf@xamarin.com)
5 //   Atsushi Enomoto (atsushi@xamarin.com)
6 //
7 // Copyright (C) 2011,2013 Xamarin Inc.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using Microsoft.Build.Evaluation;
30 using System;
31 using System.Collections.Generic;
32 using System.Threading;
33 using Microsoft.Build.Internal;
34 using System.Linq;
35
36 namespace Microsoft.Build.Execution
37 {
38         public class BuildManager
39         {
40                 static BuildManager default_manager = new BuildManager ();
41
42                 public static BuildManager DefaultBuildManager {
43                         get { return default_manager; }
44                 }
45                 
46                 public BuildManager ()
47                 {
48                 }
49
50                 public BuildManager (string hostName)
51                 {
52                         throw new NotImplementedException ();
53                 }
54                 
55                 public void Dispose ()
56                 {
57                         WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
58                         BuildNodeManager.Stop ();
59                 }
60
61                 ~BuildManager ()
62                 {
63                         // maybe processes created by out-of-process nodes should be signaled.
64                         BuildNodeManager.Stop ();
65                 }
66
67                 readonly List<BuildSubmission> submissions = new List<BuildSubmission> ();
68                 
69                 BuildParameters ongoing_build_parameters;
70                 
71                 internal BuildParameters OngoingBuildParameters {
72                         get { return ongoing_build_parameters; }
73                 }
74
75                 public void BeginBuild (BuildParameters parameters)
76                 {
77                         if (ongoing_build_parameters != null)
78                                 throw new InvalidOperationException ("There is already ongoing build");
79                         ongoing_build_parameters = parameters.Clone ();
80                 }
81
82                 public BuildResult Build (BuildParameters parameters, BuildRequestData requestData)
83                 {
84                         BeginBuild (parameters);
85                         var ret = BuildRequest (requestData);
86                         EndBuild ();
87                         return ret;
88                 }
89
90                 public BuildResult BuildRequest (BuildRequestData requestData)
91                 {
92                         var sub = PendBuildRequest (requestData);
93                         sub.Execute ();
94                         return sub.BuildResult;
95                 }
96                 
97                 public void CancelAllSubmissions ()
98                 {
99                         foreach (var sub in submissions) {
100                                 try {
101                                         if (!sub.IsCompleted)
102                                                 sub.Cancel ();
103                                 } catch (InvalidOperationException) {
104                                         // some submissions could be already done during this iteration. Ignore that.
105                                 }
106                         }
107                         submissions.Clear ();
108                 }
109
110                 public void EndBuild ()
111                 {
112                         if (ongoing_build_parameters == null)
113                                 throw new InvalidOperationException ("Build has not started");
114                         if (submissions.Count > 0)
115                                 WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
116                         BuildNodeManager.Stop ();
117                         ongoing_build_parameters = null;
118                 }
119                 
120                 Dictionary<Project,ProjectInstance> instances = new Dictionary<Project, ProjectInstance> ();
121
122                 public ProjectInstance GetProjectInstanceForBuild (Project project)
123                 {
124                         if (project == null)
125                                 throw new ArgumentNullException ("project");
126                         if (project.FullPath == null)
127                                 throw new ArgumentNullException ("project", "FullPath parameter in the project cannot be null.");
128                         if (project.FullPath == string.Empty)
129                                 throw new ArgumentException ("FullPath parameter in the project cannot be empty.", "project");
130                         // other than that, any invalid path character is accepted...
131                         
132                         return GetProjectInstanceForBuildInternal (project);
133                 }
134                         
135                 internal ProjectInstance GetProjectInstanceForBuildInternal (Project project)
136                 {
137                         if (!instances.ContainsKey (project))
138                                 instances [project] = project.CreateProjectInstance ();
139                         return instances [project];
140                 }
141
142                 public BuildSubmission PendBuildRequest (BuildRequestData requestData)
143                 {
144                         if (ongoing_build_parameters == null)
145                                 throw new InvalidOperationException ("This method cannot be called before calling BeginBuild method.");
146                         var sub = new BuildSubmission (this, requestData);
147                         submissions.Add (sub);
148                         return sub;
149                 }
150
151                 public void ResetCaches ()
152                 {
153                         if (OngoingBuildParameters != null)
154                                 throw new InvalidOperationException ("Cannot reset caches while builds are in progress.");
155                         
156                         BuildNodeManager.ResetCaches ();
157                 }
158                 
159                 BuildNodeManager build_node_manager;
160                 
161                 internal BuildNodeManager BuildNodeManager {
162                         get {
163                                 if (build_node_manager == null)
164                                                 build_node_manager = new BuildNodeManager (this);
165                                 return build_node_manager;
166                         }
167                 }
168         }
169 }