New tests.
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / MSBuild.cs
1 //
2 // MSBuild.cs: Task that can run .*proj files
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.BuildEngine;
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
37
38 namespace Microsoft.Build.Tasks {
39
40         [MonoTODO]
41         public class MSBuild : TaskExtension {
42         
43                 ITaskItem []    projects;
44                 string []       properties;
45                 bool            rebaseOutputs;
46                 bool            runEachTargetSeparately;
47                 bool            stopOnFirstFailure;
48                 bool            buildInParallel;
49                 ITaskItem []    targetOutputs;
50                 string []       targets;
51         
52                 public MSBuild ()
53                 {
54                 }
55
56                 public override bool Execute ()
57                 {
58                         if (projects.Length == 0)
59                                 return true;
60
61                         string filename;
62                         bool result = true;
63                         stopOnFirstFailure = false;
64                         List <ITaskItem > outputItems = new List <ITaskItem> ();
65                         string currentDirectory = Environment.CurrentDirectory;
66                         Hashtable outputs;
67                 
68                         var global_properties = SplitPropertiesToDictionary ();
69                         Dictionary<string, ITaskItem> projectsByFileName = new Dictionary<string, ITaskItem> ();
70
71                         Log.LogMessage (MessageImportance.Low, "Global Properties:");
72                         if (global_properties != null)
73                                 foreach (KeyValuePair<string, string> pair in global_properties)
74                                         Log.LogMessage (MessageImportance.Low, "\t{0} = {1}", pair.Key, pair.Value);
75
76                         foreach (ITaskItem project in projects) {
77                                 filename = project.GetMetadata ("FullPath");
78                                 if (!File.Exists (filename)) {
79                                         Log.LogError ("Could not find the project file '{0}'", filename);
80                                         if (stopOnFirstFailure)
81                                                 break;
82
83                                         continue;
84                                 }
85
86                                 Directory.SetCurrentDirectory (Path.GetDirectoryName (filename));
87                                 outputs = new Hashtable ();
88
89                                 try {
90                                         // Order of precedence:
91                                         // %(Project.ToolsVersion) , ToolsVersion property
92                                         string tv = project.GetMetadata ("ToolsVersion");
93                                         if (String.IsNullOrEmpty (tv))
94                                                 tv = ToolsVersion;
95                                         ThrowIfNotValidToolsVersion (tv);
96
97                                         result = BuildEngine2.BuildProjectFile (filename, targets, global_properties, outputs, tv);
98                                 } catch (InvalidProjectFileException e) {
99                                         Log.LogError ("Error building project {0}: {1}", filename, e.Message);
100                                         result = false;
101                                 }
102
103                                 if (result) {
104                                         // Metadata from the first item for the project file is copied
105                                         ITaskItem first_item;
106                                         if (!projectsByFileName.TryGetValue (filename, out first_item))
107                                                 projectsByFileName [filename] = first_item = project;
108
109                                         foreach (DictionaryEntry de in outputs) {
110                                                 ITaskItem [] array = (ITaskItem []) de.Value;
111                                                 foreach (ITaskItem item in array) {
112                                                         // DONT share items!
113                                                         ITaskItem new_item = new TaskItem (item);
114
115                                                         // copy the metadata from original @project to here
116                                                         // CopyMetadataTo does _not_ overwrite
117                                                         first_item.CopyMetadataTo (new_item);
118
119                                                         outputItems.Add (new_item);
120
121                                                         //FIXME: Correctly rebase output paths to be relative to the
122                                                         //       calling project
123                                                         //if (rebaseOutputs)
124                                                         //      File.Copy (item.ItemSpec, Path.Combine (currentDirectory, item.ItemSpec), true);
125                                                 }
126                                         }
127                                 } else {
128                                         if (stopOnFirstFailure)
129                                                 break;
130                                 }
131
132                                 Directory.SetCurrentDirectory (currentDirectory);
133                         }
134
135                         if (result)
136                                 targetOutputs = outputItems.ToArray ();
137
138                         Directory.SetCurrentDirectory (currentDirectory);
139                         return result;
140                 }
141
142                 void ThrowIfNotValidToolsVersion (string toolsVersion)
143                 {
144                         if (!String.IsNullOrEmpty (toolsVersion) && Engine.GlobalEngine.Toolsets [toolsVersion] == null)
145                                 throw new Exception (String.Format ("Unknown ToolsVersion : {0}", toolsVersion));
146                 }
147
148                 [Required]
149                 public ITaskItem [] Projects {
150                         get { return projects; }
151                         set { projects = value; }
152                 }
153
154                 [MonoTODO]
155                 public string [] Properties {
156                         get { return properties; }
157                         set { properties = value; }
158                 }
159
160                 public bool RebaseOutputs {
161                         get { return rebaseOutputs; }
162                         set { rebaseOutputs = value; }
163                 }
164
165                 [MonoTODO]
166                 public bool RunEachTargetSeparately {
167                         get { return runEachTargetSeparately; }
168                         set { runEachTargetSeparately = value; }
169                 }
170
171                 public bool StopOnFirstFailure {
172                         get { return stopOnFirstFailure; }
173                         set { stopOnFirstFailure = value; }
174                 }
175
176                 [Output]
177                 public ITaskItem [] TargetOutputs {
178                         get { return targetOutputs; }
179                 }
180
181                 public string [] Targets {
182                         get { return targets; }
183                         set { targets = value; }
184                 }
185
186                 public bool BuildInParallel {
187                         get { return buildInParallel; }
188                         set { buildInParallel = value; }
189                 }
190
191                 public string ToolsVersion {
192                         get; set;
193                 }
194
195                 SortedDictionary<string, string> SplitPropertiesToDictionary ()
196                 {
197                         if (properties == null)
198                                 return null;
199
200                         var global_properties = new SortedDictionary<string, string> ();
201                         foreach (string kvpair in properties) {
202                                 if (String.IsNullOrEmpty (kvpair))
203                                         continue;
204
205                                 string [] parts = kvpair.Trim ().Split (new char [] {'='}, 2);
206                                 if (parts.Length != 2) {
207                                         Log.LogWarning ("Invalid key/value pairs ({0}) in Properties, ignoring.", kvpair);
208                                         continue;
209                                 }
210
211                                 global_properties.Add (parts [0], parts [1]);
212                         }
213
214                         return global_properties;
215                 }
216
217         }
218 }
219
220 #endif