Merge pull request #995 from yjoly/master
[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 // Copyright 2011 Xamarin Inc
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 #if NET_2_0
30
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.IO;
35 using Microsoft.Build.BuildEngine;
36 using Microsoft.Build.Framework;
37 using Microsoft.Build.Utilities;
38
39 namespace Microsoft.Build.Tasks {
40
41         [MonoTODO]
42         public class MSBuild : TaskExtension {
43         
44                 ITaskItem []    projects;
45                 string []       properties;
46                 bool            rebaseOutputs;
47                 bool            runEachTargetSeparately;
48                 bool            stopOnFirstFailure;
49                 bool            buildInParallel;
50                 ITaskItem []    targetOutputs;
51                 string []       targets;
52         
53                 public MSBuild ()
54                 {
55                 }
56
57                 public override bool Execute ()
58                 {
59                         if (projects.Length == 0)
60                                 return true;
61
62                         string filename;
63                         bool result = true;
64                         bool all_result = true;
65                         stopOnFirstFailure = false;
66                         List <ITaskItem > outputItems = new List <ITaskItem> ();
67                         string currentDirectory = Environment.CurrentDirectory;
68                         Hashtable outputs;
69                 
70                         var global_properties = SplitPropertiesToDictionary ();
71
72                         Log.LogMessage (MessageImportance.Low, "Global Properties:");
73                         if (global_properties != null)
74                                 foreach (KeyValuePair<string, string> pair in global_properties)
75                                         Log.LogMessage (MessageImportance.Low, "\t{0} = {1}", pair.Key, pair.Value);
76
77                         foreach (ITaskItem project in projects) {
78                                 filename = project.GetMetadata ("FullPath");
79                                 if (!File.Exists (filename)) {
80                                         Log.LogError ("Could not find the project file '{0}'", filename);
81                                         if (stopOnFirstFailure)
82                                                 break;
83
84                                         continue;
85                                 }
86
87                                 Directory.SetCurrentDirectory (Path.GetDirectoryName (filename));
88                                 outputs = new Hashtable ();
89
90                                 try {
91                                         // Order of precedence:
92                                         // ToolsVersion property, %(Project.ToolsVersion)
93                                         string tv = ToolsVersion;
94                                         if (String.IsNullOrEmpty (tv))
95                                                 // metadata on the Project item
96                                                 tv = project.GetMetadata ("ToolsVersion");
97
98                                         if (!String.IsNullOrEmpty (tv) && Engine.GlobalEngine.Toolsets [tv] == null)
99                                                 throw new UnknownToolsVersionException (tv);
100
101                                         result = BuildEngine2.BuildProjectFile (filename, targets, global_properties, outputs, tv);
102                                 } catch (InvalidProjectFileException e) {
103                                         Log.LogError ("Error building project {0}: {1}", filename, e.Message);
104                                         result = false;
105                                 }
106
107                                 if (!result)
108                                         all_result = false;
109
110                                 if (result) {
111                                         foreach (DictionaryEntry de in outputs) {
112                                                 ITaskItem [] array = (ITaskItem []) de.Value;
113                                                 foreach (ITaskItem item in array) {
114                                                         // DONT share items!
115                                                         ITaskItem new_item = new TaskItem (item);
116
117                                                         // copy the metadata from original @project to here
118                                                         // CopyMetadataTo does _not_ overwrite
119                                                         project.CopyMetadataTo (new_item);
120
121                                                         outputItems.Add (new_item);
122
123                                                         //FIXME: Correctly rebase output paths to be relative to the
124                                                         //       calling project
125                                                         //if (rebaseOutputs)
126                                                         //      File.Copy (item.ItemSpec, Path.Combine (currentDirectory, item.ItemSpec), true);
127                                                 }
128                                         }
129                                 } else {
130                                         if (stopOnFirstFailure)
131                                                 break;
132                                 }
133
134                                 Directory.SetCurrentDirectory (currentDirectory);
135                         }
136
137                         if (all_result)
138                                 targetOutputs = outputItems.ToArray ();
139
140                         Directory.SetCurrentDirectory (currentDirectory);
141                         return all_result;
142                 }
143
144                 void ThrowIfInvalidToolsVersion (string toolsVersion)
145                 {
146                         if (!String.IsNullOrEmpty (toolsVersion) && Engine.GlobalEngine.Toolsets [toolsVersion] == null)
147                                 throw new UnknownToolsVersionException (toolsVersion);
148                 }
149
150                 [Required]
151                 public ITaskItem [] Projects {
152                         get { return projects; }
153                         set { projects = value; }
154                 }
155
156                 [MonoTODO]
157                 public string [] Properties {
158                         get { return properties; }
159                         set { properties = value; }
160                 }
161
162                 public bool RebaseOutputs {
163                         get { return rebaseOutputs; }
164                         set { rebaseOutputs = value; }
165                 }
166
167                 [MonoTODO]
168                 public bool RunEachTargetSeparately {
169                         get { return runEachTargetSeparately; }
170                         set { runEachTargetSeparately = value; }
171                 }
172
173                 public bool StopOnFirstFailure {
174                         get { return stopOnFirstFailure; }
175                         set { stopOnFirstFailure = value; }
176                 }
177
178                 [Output]
179                 public ITaskItem [] TargetOutputs {
180                         get { return targetOutputs; }
181                 }
182
183                 public string [] Targets {
184                         get { return targets; }
185                         set { targets = value; }
186                 }
187
188                 public bool BuildInParallel {
189                         get { return buildInParallel; }
190                         set { buildInParallel = value; }
191                 }
192
193                 public string ToolsVersion {
194                         get; set;
195                 }
196
197                 SortedDictionary<string, string> SplitPropertiesToDictionary ()
198                 {
199                         if (properties == null)
200                                 return null;
201
202                         var global_properties = new SortedDictionary<string, string> ();
203                         foreach (string kvpair in properties) {
204                                 if (String.IsNullOrEmpty (kvpair))
205                                         continue;
206
207                                 string [] parts = kvpair.Trim ().Split (new char [] {'='}, 2);
208                                 if (parts.Length != 2) {
209                                         Log.LogWarning ("Invalid key/value pairs ({0}) in Properties, ignoring.", kvpair);
210                                         continue;
211                                 }
212
213                                 global_properties.Add (parts [0], parts [1]);
214                         }
215
216                         return global_properties;
217                 }
218
219         }
220 }
221
222 #endif