2 // MSBuild.cs: Task that can run .*proj files
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
8 // Copyright 2011 Xamarin Inc
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
32 using System.Collections;
33 using System.Collections.Generic;
35 using Microsoft.Build.BuildEngine;
36 using Microsoft.Build.Framework;
37 using Microsoft.Build.Utilities;
39 namespace Microsoft.Build.Tasks {
42 public class MSBuild : TaskExtension {
44 ITaskItem [] projects;
47 bool runEachTargetSeparately;
48 bool stopOnFirstFailure;
50 ITaskItem [] targetOutputs;
57 public override bool Execute ()
59 if (projects.Length == 0)
64 bool all_result = true;
65 stopOnFirstFailure = false;
66 List <ITaskItem > outputItems = new List <ITaskItem> ();
67 string currentDirectory = Environment.CurrentDirectory;
70 var global_properties = SplitPropertiesToDictionary ();
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);
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)
87 Directory.SetCurrentDirectory (Path.GetDirectoryName (filename));
88 outputs = new Hashtable ();
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");
98 if (!String.IsNullOrEmpty (tv) && Engine.GlobalEngine.Toolsets [tv] == null)
99 throw new UnknownToolsVersionException (tv);
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);
111 foreach (DictionaryEntry de in outputs) {
112 ITaskItem [] array = (ITaskItem []) de.Value;
113 foreach (ITaskItem item in array) {
115 ITaskItem new_item = new TaskItem (item);
117 // copy the metadata from original @project to here
118 // CopyMetadataTo does _not_ overwrite
119 project.CopyMetadataTo (new_item);
121 outputItems.Add (new_item);
123 //FIXME: Correctly rebase output paths to be relative to the
126 // File.Copy (item.ItemSpec, Path.Combine (currentDirectory, item.ItemSpec), true);
130 if (stopOnFirstFailure)
134 Directory.SetCurrentDirectory (currentDirectory);
138 targetOutputs = outputItems.ToArray ();
140 Directory.SetCurrentDirectory (currentDirectory);
144 void ThrowIfInvalidToolsVersion (string toolsVersion)
146 if (!String.IsNullOrEmpty (toolsVersion) && Engine.GlobalEngine.Toolsets [toolsVersion] == null)
147 throw new UnknownToolsVersionException (toolsVersion);
151 public ITaskItem [] Projects {
152 get { return projects; }
153 set { projects = value; }
157 public string [] Properties {
158 get { return properties; }
159 set { properties = value; }
162 public bool RebaseOutputs {
163 get { return rebaseOutputs; }
164 set { rebaseOutputs = value; }
168 public bool RunEachTargetSeparately {
169 get { return runEachTargetSeparately; }
170 set { runEachTargetSeparately = value; }
173 public bool StopOnFirstFailure {
174 get { return stopOnFirstFailure; }
175 set { stopOnFirstFailure = value; }
179 public ITaskItem [] TargetOutputs {
180 get { return targetOutputs; }
183 public string [] Targets {
184 get { return targets; }
185 set { targets = value; }
188 public bool BuildInParallel {
189 get { return buildInParallel; }
190 set { buildInParallel = value; }
193 public string ToolsVersion {
197 SortedDictionary<string, string> SplitPropertiesToDictionary ()
199 if (properties == null)
202 var global_properties = new SortedDictionary<string, string> ();
203 foreach (string kvpair in properties) {
204 if (String.IsNullOrEmpty (kvpair))
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);
213 global_properties.Add (parts [0], parts [1]);
216 return global_properties;