2007-02-03 Marek Sieradzki <marek.sieradzki@gmail.com>
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Engine.cs
1 //
2 // Engine.cs: Main engine of XBuild.
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 // 
7 // (C) 2005 Marek Sieradzki
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 #if NET_2_0
29
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.IO;
34 using Microsoft.Build.Framework;
35 using Mono.XBuild.Utilities;
36
37 namespace Microsoft.Build.BuildEngine {
38         public class Engine {
39                 
40                 string                  binPath;
41                 bool                    buildEnabled;
42                 TaskDatabase            defaultTasks;
43                 bool                    defaultTasksRegistered;
44                 const string            defaultTasksProjectName = "Microsoft.Common.tasks";
45                 EventSource             eventSource;
46                 bool                    buildStarted;
47                 BuildPropertyGroup      globalProperties;
48                 //IDictionary           importedProjects;
49                 List <ILogger>          loggers;
50                 //bool                  onlyLogCriticalEvents;
51                 Dictionary <string, Project>    projects;
52
53                 static Engine           globalEngine;
54                 static Version          version;
55
56                 static Engine ()
57                 {
58                         version = new Version ("0.1");
59                 }
60                 
61                 public Engine ()
62                         : this (null)
63                 {
64                 }
65
66                 // engine should be invoked with path where binary files are
67                 // to find microsoft.build.tasks
68                 public Engine (string binPath)
69                 {
70                         this.binPath = binPath;
71                         this.buildEnabled = true;
72                         this.projects = new Dictionary <string, Project> ();
73                         this.eventSource = new EventSource ();
74                         this.loggers = new List <ILogger> ();
75                         this.buildStarted = false;
76                         this.globalProperties = new BuildPropertyGroup ();
77                         
78                         RegisterDefaultTasks ();
79                 }
80                 
81                 [MonoTODO]
82                 public bool BuildProject (Project project)
83                 {
84                         return project.Build ();
85                 }
86                 
87                 [MonoTODO]
88                 public bool BuildProject (Project project, string targetName)
89                 {
90                         return BuildProject (project, new string[] { targetName}, null, BuildSettings.None);
91                 }
92                 
93                 [MonoTODO]
94                 public bool BuildProject (Project project, string[] targetNames)
95                 {
96                         return BuildProject (project, targetNames, null, BuildSettings.None);
97                 }
98
99                 [MonoTODO]
100                 public bool BuildProject (Project project,
101                                           string[] targetNames,
102                                           IDictionary targetOutputs)
103                 {
104                         return BuildProject (project, targetNames, targetOutputs, BuildSettings.None);
105                 }
106                 
107                 [MonoTODO ("use buildFlags")]
108                 public bool BuildProject (Project project,
109                                           string[] targetNames,
110                                           IDictionary targetOutputs,
111                                           BuildSettings buildFlags)
112                 {
113                         bool result;
114
115                         StartBuild ();
116                         
117                         LogProjectStarted (project, targetNames);
118                                 
119                         result =  project.Build (targetNames, targetOutputs);
120                         
121                         LogProjectFinished (project, result);
122                         
123                         return result;
124                 }
125
126                 [MonoTODO]
127                 public bool BuildProjectFile (string projectFile)
128                 {
129                         throw new NotImplementedException ();
130                 }
131                 
132                 [MonoTODO]
133                 public bool BuildProjectFile (string projectFile,
134                                               string targetName)
135                 {
136                         throw new NotImplementedException ();
137                 }
138                 
139                 [MonoTODO]
140                 public bool BuildProjectFile (string projectFile,
141                                               string[] targetNames)
142                 {
143                         throw new NotImplementedException ();
144                 }
145                 
146                 [MonoTODO]
147                 public bool BuildProjectFile (string projectFile,
148                                               string[] targetNames,
149                                               BuildPropertyGroup globalProperties)
150                 {
151                         return BuildProjectFile (projectFile, targetNames, globalProperties, null, BuildSettings.None);
152                 }
153                 
154                 [MonoTODO]
155                 public bool BuildProjectFile (string projectFile,
156                                               string[] targetNames,
157                                               BuildPropertyGroup globalProperties,
158                                               IDictionary targetOutputs)
159                 {
160                         return BuildProjectFile (projectFile, targetNames, globalProperties, targetOutputs, BuildSettings.None);
161                 }
162                 
163                 [MonoTODO ("use buildFlags")]
164                 public bool BuildProjectFile (string projectFile,
165                                               string[] targetNames,
166                                               BuildPropertyGroup globalProperties,
167                                               IDictionary targetOutputs,
168                                               BuildSettings buildFlags)
169                 {
170                         bool result;
171                         Project project;
172
173                         StartBuild ();
174                         
175                         if (projects.ContainsKey (projectFile)) {
176                                 project = (Project) projects [projectFile];
177                                 LogProjectStarted (project, targetNames);
178                                 result = project.Build (targetNames, targetOutputs);
179                         } else {
180                                 project = CreateNewProject ();
181                                 project.Load (projectFile);
182                                 LogProjectStarted (project, targetNames);
183                                 result = project.Build (targetNames, targetOutputs);
184                         }
185                         
186                         LogProjectFinished (project, result);
187                         
188                         return result;
189                 }
190
191                 void CheckBinPath ()
192                 {
193                         if (BinPath == null) {
194                                 throw new InvalidOperationException ("Before a project can be instantiated, " +
195                                         "Engine.BinPath must be set to the location on disk where MSBuild " + 
196                                         "is installed. This is used to evaluate $(MSBuildBinPath).");
197                         }
198                 }
199
200                 public Project CreateNewProject ()
201                 {
202                         if (defaultTasksRegistered)
203                                 CheckBinPath ();
204                         return new Project (this);
205                 }
206
207                 public Project GetLoadedProject (string projectFullFileName)
208                 {
209                         if (projectFullFileName == null)
210                                 throw new ArgumentNullException ("projectFullFileName");
211                         
212                         // FIXME: test it
213                         return projects [projectFullFileName];
214                 }
215
216                 internal void RemoveLoadedProject (Project p)
217                 {
218                         if (p.FullFileName != String.Empty)
219                                 projects.Remove (p.FullFileName);
220                 }
221
222                 internal void AddLoadedProject (Project p)
223                 {
224                         if (p.FullFileName != String.Empty)
225                                 projects.Add (p.FullFileName, p);
226                 }
227         
228                 public void UnloadProject (Project project)
229                 {
230                         if (project == null)
231                                 throw new ArgumentNullException ("project");
232
233                         if (project.ParentEngine != this)
234                                 throw new InvalidOperationException ("The \"Project\" object specified does not belong to the correct \"Engine\" object.");
235                         
236                         project.CheckUnloaded ();
237                         
238                         if (project.FullFileName != String.Empty)
239                                 projects.Remove (project.FullFileName);
240                         
241                         project.Unload ();
242                 }
243
244                 public void UnloadAllProjects ()
245                 {
246                         foreach (KeyValuePair <string, Project> e in projects)
247                                 UnloadProject (e.Value);
248                 }
249
250                 [MonoTODO]
251                 public void RegisterLogger (ILogger logger)
252                 {
253                         if (logger == null)
254                                 throw new ArgumentNullException ("logger");
255                         
256                         logger.Initialize (eventSource);
257                         loggers.Add (logger);
258                 }
259                 
260                 [MonoTODO]
261                 public void UnregisterAllLoggers ()
262                 {
263                         // FIXME: check if build succeeded
264                         // FIXME: it shouldn't be here
265                         LogBuildFinished (true);
266                         foreach (ILogger i in loggers) {
267                                 i.Shutdown ();
268                         }
269                         loggers.Clear ();
270                 }
271
272                 internal void StartBuild ()
273                 {
274                         if (!buildStarted) {
275                                 LogBuildStarted ();
276                                 buildStarted = true;
277                         }
278                 }
279                 
280                 void LogProjectStarted (Project project, string [] targetNames)
281                 {
282                         ProjectStartedEventArgs psea;
283                         if (targetNames.Length == 0) {
284                                 if (project.DefaultTargets != String.Empty)
285                                         psea = new ProjectStartedEventArgs ("Project started.", null, project.FullFileName,
286                                                 project.DefaultTargets, null, null);
287                                 else
288                                         psea = new ProjectStartedEventArgs ("Project started.", null, project.FullFileName, "default", null, null);
289                         } else
290                         psea = new ProjectStartedEventArgs ("Project started.", null, project.FullFileName, String.Join (";",
291                                 targetNames), null, null);
292                         eventSource.FireProjectStarted (this, psea);
293                 }
294                 
295                 void LogProjectFinished (Project project, bool succeeded)
296                 {
297                         ProjectFinishedEventArgs pfea;
298                         pfea = new ProjectFinishedEventArgs ("Project started.", null, project.FullFileName, succeeded);
299                         eventSource.FireProjectFinished (this, pfea);
300                 }
301                 
302                 void LogBuildStarted ()
303                 {
304                         BuildStartedEventArgs bsea;
305                         bsea = new BuildStartedEventArgs ("Build started.", null);
306                         eventSource.FireBuildStarted (this, bsea);
307                 }
308                 
309                 void LogBuildFinished (bool succeeded)
310                 {
311                         BuildFinishedEventArgs bfea;
312                         bfea = new BuildFinishedEventArgs ("Build finished.", null, succeeded);
313                         eventSource.FireBuildFinished (this, bfea);
314                 }
315                 
316                 void RegisterDefaultTasks ()
317                 {
318                         this.defaultTasksRegistered = false;
319                         
320                         Project defaultTasksProject = CreateNewProject ();
321                         
322                         if (binPath != null) {
323                                 if (File.Exists (Path.Combine (binPath, defaultTasksProjectName))) {
324                                         defaultTasksProject.Load (Path.Combine (binPath, defaultTasksProjectName));
325                                         defaultTasks = defaultTasksProject.TaskDatabase;
326                                 } else
327                                         defaultTasks = new TaskDatabase ();
328                         } else
329                                 defaultTasks = new TaskDatabase ();
330                         
331                         this.defaultTasksRegistered = true;
332                 }
333
334                 public string BinPath {
335                         get { return binPath; }
336                         set { binPath = value; }
337                 }
338
339                 public bool BuildEnabled {
340                         get { return buildEnabled; }
341                         set { buildEnabled = value; }
342                 }
343
344                 public static Version Version {
345                         get { return version; }
346                 }
347
348                 public static Engine GlobalEngine {
349                         get {
350                                 if (globalEngine == null)
351                                         globalEngine = new Engine ();
352                                 return globalEngine;
353                         }
354                 }
355
356                 public BuildPropertyGroup GlobalProperties {
357                         get { return globalProperties; }
358                         set { globalProperties = value; }
359                 }
360
361                 public bool OnlyLogCriticalEvents {
362                         get { return eventSource.OnlyLogCriticalEvents; }
363                         set { eventSource.OnlyLogCriticalEvents = value; }
364                 }
365                 
366                 internal EventSource EventSource {
367                         get { return eventSource; }
368                 }
369                 
370                 internal bool DefaultTasksRegistered {
371                         get { return defaultTasksRegistered; }
372                 }
373                 
374                 internal TaskDatabase DefaultTasks {
375                         get { return defaultTasks; }
376                 }
377         }
378 }
379
380 #endif