2 // MSBuild.cs: Task that can run .*proj files
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
31 using System.Collections;
32 using System.Collections.Generic;
34 using Microsoft.Build.BuildEngine;
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
38 namespace Microsoft.Build.Tasks {
41 public class MSBuild : TaskExtension {
43 ITaskItem [] projects;
46 bool runEachTargetSeparately;
47 bool stopOnFirstFailure;
49 ITaskItem [] targetOutputs;
56 public override bool Execute ()
58 if (projects.Length == 0)
63 stopOnFirstFailure = false;
64 List <ITaskItem > outputItems = new List <ITaskItem> ();
65 string currentDirectory = Environment.CurrentDirectory;
68 var global_properties = SplitPropertiesToDictionary ();
69 Dictionary<string, ITaskItem> projectsByFileName = new Dictionary<string, ITaskItem> ();
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);
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)
86 Directory.SetCurrentDirectory (Path.GetDirectoryName (filename));
87 outputs = new Hashtable ();
90 // Order of precedence:
91 // %(Project.ToolsVersion) , ToolsVersion property
92 string tv = project.GetMetadata ("ToolsVersion");
93 if (String.IsNullOrEmpty (tv))
95 ThrowIfNotValidToolsVersion (tv);
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);
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;
109 foreach (DictionaryEntry de in outputs) {
110 ITaskItem [] array = (ITaskItem []) de.Value;
111 foreach (ITaskItem item in array) {
113 ITaskItem new_item = new TaskItem (item);
115 // copy the metadata from original @project to here
116 // CopyMetadataTo does _not_ overwrite
117 first_item.CopyMetadataTo (new_item);
119 outputItems.Add (new_item);
121 //FIXME: Correctly rebase output paths to be relative to the
124 // File.Copy (item.ItemSpec, Path.Combine (currentDirectory, item.ItemSpec), true);
128 if (stopOnFirstFailure)
132 Directory.SetCurrentDirectory (currentDirectory);
136 targetOutputs = outputItems.ToArray ();
138 Directory.SetCurrentDirectory (currentDirectory);
142 void ThrowIfNotValidToolsVersion (string toolsVersion)
144 if (!String.IsNullOrEmpty (toolsVersion) && Engine.GlobalEngine.Toolsets [toolsVersion] == null)
145 throw new Exception (String.Format ("Unknown ToolsVersion : {0}", toolsVersion));
149 public ITaskItem [] Projects {
150 get { return projects; }
151 set { projects = value; }
155 public string [] Properties {
156 get { return properties; }
157 set { properties = value; }
160 public bool RebaseOutputs {
161 get { return rebaseOutputs; }
162 set { rebaseOutputs = value; }
166 public bool RunEachTargetSeparately {
167 get { return runEachTargetSeparately; }
168 set { runEachTargetSeparately = value; }
171 public bool StopOnFirstFailure {
172 get { return stopOnFirstFailure; }
173 set { stopOnFirstFailure = value; }
177 public ITaskItem [] TargetOutputs {
178 get { return targetOutputs; }
181 public string [] Targets {
182 get { return targets; }
183 set { targets = value; }
186 public bool BuildInParallel {
187 get { return buildInParallel; }
188 set { buildInParallel = value; }
191 public string ToolsVersion {
195 SortedDictionary<string, string> SplitPropertiesToDictionary ()
197 if (properties == null)
200 var global_properties = new SortedDictionary<string, string> ();
201 foreach (string kvpair in properties) {
202 if (String.IsNullOrEmpty (kvpair))
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);
211 global_properties.Add (parts [0], parts [1]);
214 return global_properties;