c186bbca2deb80ffcbe781f598fbdf1e6e2ad5fe
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Evaluation / Project.cs
1 //
2 // Project.cs
3 //
4 // Author:
5 //   Leszek Ciesielski (skolima@gmail.com)
6 //   Rolf Bjarne Kvinge (rolf@xamarin.com)
7 //
8 // (C) 2011 Leszek Ciesielski
9 // Copyright (C) 2011 Xamarin Inc. (http://www.xamarin.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Collections.Generic;
33 using System.Diagnostics;
34 using System.IO;
35 using System.Linq;
36 using System.Text;
37 using System.Xml;
38 using Microsoft.Build.Construction;
39 using Microsoft.Build.Internal;
40 using Microsoft.Build.Execution;
41 using Microsoft.Build.Framework;
42 using Microsoft.Build.Logging;
43 using System.Collections;
44
45 namespace Microsoft.Build.Evaluation
46 {
47         [DebuggerDisplay ("{FullPath} EffectiveToolsVersion={ToolsVersion} #GlobalProperties="
48         + "{data.globalProperties.Count} #Properties={data.Properties.Count} #ItemTypes="
49         + "{data.ItemTypes.Count} #ItemDefinitions={data.ItemDefinitions.Count} #Items="
50         + "{data.Items.Count} #Targets={data.Targets.Count}")]
51         public class Project
52         {
53                 public Project (XmlReader xml)
54                         : this (ProjectRootElement.Create (xml))
55                 {
56                 }
57
58                 public Project (XmlReader xml, IDictionary<string, string> globalProperties,
59                                               string toolsVersion)
60                         : this (ProjectRootElement.Create (xml), globalProperties, toolsVersion)
61                 {
62                 }
63
64                 public Project (XmlReader xml, IDictionary<string, string> globalProperties,
65                                               string toolsVersion, ProjectCollection projectCollection)
66                         : this (ProjectRootElement.Create (xml), globalProperties, toolsVersion, projectCollection)
67                 {
68                 }
69
70                 public Project (XmlReader xml, IDictionary<string, string> globalProperties,
71                                               string toolsVersion, ProjectCollection projectCollection,
72                                               ProjectLoadSettings loadSettings)
73                         : this (ProjectRootElement.Create (xml), globalProperties, toolsVersion, projectCollection, loadSettings)
74                 {
75                 }
76
77                 public Project (ProjectRootElement xml) : this (xml, null, null)
78                 {
79                 }
80
81                 public Project (ProjectRootElement xml, IDictionary<string, string> globalProperties,
82                                               string toolsVersion)
83                         : this (xml, globalProperties, toolsVersion, ProjectCollection.GlobalProjectCollection)
84                 {
85                 }
86
87                 public Project (ProjectRootElement xml, IDictionary<string, string> globalProperties,
88                                               string toolsVersion, ProjectCollection projectCollection)
89                         : this (xml, globalProperties, toolsVersion, projectCollection, ProjectLoadSettings.Default)
90                 {
91                 }
92
93                 public Project (ProjectRootElement xml, IDictionary<string, string> globalProperties,
94                                               string toolsVersion, ProjectCollection projectCollection,
95                                               ProjectLoadSettings loadSettings)
96                 {
97                         if (projectCollection == null)
98                                 throw new ArgumentNullException ("projectCollection");
99                         this.Xml = xml;
100                         this.GlobalProperties = globalProperties ?? new Dictionary<string, string> ();
101                         this.ToolsVersion = toolsVersion;
102                         this.ProjectCollection = projectCollection;
103                         this.load_settings = loadSettings;
104
105                         Initialize ();
106                 }
107
108                 public Project (string projectFile)
109                         : this (projectFile, null, null)
110                 {
111                 }
112
113                 public Project (string projectFile, IDictionary<string, string> globalProperties,
114                                 string toolsVersion)
115                 : this (projectFile, globalProperties, toolsVersion, ProjectCollection.GlobalProjectCollection, ProjectLoadSettings.Default)
116                 {
117                 }
118
119                 public Project (string projectFile, IDictionary<string, string> globalProperties,
120                                 string toolsVersion, ProjectCollection projectCollection)
121                 : this (projectFile, globalProperties, toolsVersion, projectCollection, ProjectLoadSettings.Default)
122                 {
123                 }
124
125                 public Project (string projectFile, IDictionary<string, string> globalProperties,
126                                 string toolsVersion, ProjectCollection projectCollection,
127                                 ProjectLoadSettings loadSettings)
128                         : this (ProjectRootElement.Create (projectFile), globalProperties, toolsVersion, projectCollection, loadSettings)
129                 {
130                 }
131
132                 ProjectLoadSettings load_settings;
133
134                 public IDictionary<string, string> GlobalProperties { get; private set; }
135
136                 public ProjectCollection ProjectCollection { get; private set; }
137
138                 public string ToolsVersion { get; private set; }
139
140                 public ProjectRootElement Xml { get; private set; }
141
142                 string dir_path;
143                 Dictionary<string, ProjectItemDefinition> item_definitions;
144                 List<ResolvedImport> raw_imports;
145                 List<ProjectItem> raw_items;
146                 List<string> item_types;
147                 List<ProjectProperty> properties;
148                 Dictionary<string, ProjectTargetInstance> targets;
149
150                 void Initialize ()
151                 {
152                         dir_path = Directory.GetCurrentDirectory ();
153                         raw_imports = new List<ResolvedImport> ();
154                         item_definitions = new Dictionary<string, ProjectItemDefinition> ();
155                         item_types = new List<string> ();
156                         properties = new List<ProjectProperty> ();
157                         targets = new Dictionary<string, ProjectTargetInstance> ();
158                         
159                         ProcessXml ();
160                 }
161                 
162                 void ProcessXml ()
163                 {
164                         foreach (DictionaryEntry p in Environment.GetEnvironmentVariables ())
165                                 this.properties.Add (new EnvironmentProjectProperty (this, (string)p.Key, (string)p.Value));
166                         foreach (var p in GlobalProperties)
167                                 this.properties.Add (new GlobalProjectProperty (this, p.Key, p.Value));
168                         foreach (var child in Xml.Children) {
169                                 if (child is ProjectPropertyGroupElement)
170                                         foreach (var p in ((ProjectPropertyGroupElement) child).Properties)
171                                                 this.properties.Add (new XmlProjectProperty (this, p, PropertyType.Normal));
172                                 else if (child is ProjectItemGroupElement)
173                                         foreach (var p in ((ProjectItemGroupElement) child).Items)
174                                                 this.raw_items.Add (new ProjectItem (p));
175                                 else if (child is ProjectItemDefinitionGroupElement)
176                                         foreach (var p in ((ProjectItemDefinitionGroupElement) child).ItemDefinitions) {
177                                                 ProjectItemDefinition existing;
178                                                 if (!item_definitions.TryGetValue (p.ItemType, out existing))
179                                                         item_definitions.Add (p.ItemType, (existing = new ProjectItemDefinition (this, p.ItemType)));
180                                                 existing.AddItems (p);
181                                         }
182                         }
183                 }
184
185                 public ICollection<ProjectItem> GetItemsIgnoringCondition (string itemType)
186                 {
187                         return new CollectionFromEnumerable<ProjectItem> (
188                                 new FilteredEnumerable<ProjectItemElement> (Xml.Items).
189                                 Where (p => p.ItemType.Equals (itemType, StringComparison.OrdinalIgnoreCase)).
190                                 Select (p => new ProjectItem (p)));
191                 }
192
193                 public void RemoveItems (IEnumerable<ProjectItem> items)
194                 {
195                         var removal = new List<ProjectItem> (items);
196                         foreach (var item in removal) {
197                                 var parent = item.Xml.Parent;
198                                 parent.RemoveChild (item.Xml);
199                                 if (parent.Count == 0)
200                                         parent.Parent.RemoveChild (parent);
201                         }
202                 }
203
204                 static readonly Dictionary<string, string> empty_metadata = new Dictionary<string, string> ();
205
206                 public IList<ProjectItem> AddItem (string itemType, string unevaluatedInclude)
207                 {
208                         return AddItem (itemType, unevaluatedInclude, empty_metadata);
209                 }
210
211                 public IList<ProjectItem> AddItem (string itemType, string unevaluatedInclude,
212                                 IEnumerable<KeyValuePair<string, string>> metadata)
213                 {
214                         // FIXME: needs several check that AddItemFast() does not process (see MSDN for details).
215
216                         return AddItemFast (itemType, unevaluatedInclude, metadata);
217                 }
218
219                 public IList<ProjectItem> AddItemFast (string itemType, string unevaluatedInclude)
220                 {
221                         return AddItemFast (itemType, unevaluatedInclude, empty_metadata);
222                 }
223
224                 public IList<ProjectItem> AddItemFast (string itemType, string unevaluatedInclude,
225                                                                      IEnumerable<KeyValuePair<string, string>> metadata)
226                 {
227                         throw new NotImplementedException ();
228                 }
229
230                 public bool Build ()
231                 {
232                         return Build (Xml.DefaultTargets.Split (';'));
233                 }
234
235                 public bool Build (IEnumerable<ILogger> loggers)
236                 {
237                         return Build (Xml.DefaultTargets.Split (';'), loggers);
238                 }
239
240                 public bool Build (string target)
241                 {
242                         return string.IsNullOrWhiteSpace (target) ? Build () : Build (new string [] {target});
243                 }
244
245                 public bool Build (string[] targets)
246                 {
247                         return Build (targets, new ILogger [0]);
248                 }
249
250                 public bool Build (ILogger logger)
251                 {
252                         return Build (Xml.DefaultTargets.Split (';'), new ILogger [] {logger});
253                 }
254
255                 public bool Build (string[] targets, IEnumerable<ILogger> loggers)
256                 {
257                         return Build (targets, loggers, new ForwardingLoggerRecord [0]);
258                 }
259
260                 public bool Build (IEnumerable<ILogger> loggers, IEnumerable<ForwardingLoggerRecord> remoteLoggers)
261                 {
262                         return Build (Xml.DefaultTargets.Split (';'), loggers, remoteLoggers);
263                 }
264
265                 public bool Build (string target, IEnumerable<ILogger> loggers)
266                 {
267                         return Build (new string [] { target }, loggers);
268                 }
269
270                 public bool Build (string[] targets, IEnumerable<ILogger> loggers, IEnumerable<ForwardingLoggerRecord> remoteLoggers)
271                 {
272                         // Unlike ProjectInstance.Build(), there is no place to fill outputs by targets, so ignore them
273                         // (i.e. we don't use the overload with output).
274                         //
275                         // This does not check FullPath, so don't call GetProjectInstanceForBuild() directly.
276                         return new BuildManager ().GetProjectInstanceForBuildInternal (this).Build (targets, loggers, remoteLoggers);
277                 }
278
279                 public bool Build (string target, IEnumerable<ILogger> loggers, IEnumerable<ForwardingLoggerRecord> remoteLoggers)
280                 {
281                         return Build (new string [] { target }, loggers, remoteLoggers);
282                 }
283
284                 public ProjectInstance CreateProjectInstance ()
285                 {
286                         var ret = new ProjectInstance (Xml, GlobalProperties, ToolsVersion, ProjectCollection);
287                         // FIXME: maybe fill other properties to the result.
288                         return ret;
289                 }
290
291                 public string ExpandString (string unexpandedValue)
292                 {
293                         throw new NotImplementedException ();
294                 }
295
296                 public static string GetEvaluatedItemIncludeEscaped (ProjectItem item)
297                 {
298                         throw new NotImplementedException ();
299                 }
300
301                 public static string GetEvaluatedItemIncludeEscaped (ProjectItemDefinition item)
302                 {
303                         throw new NotImplementedException ();
304                 }
305
306                 public ICollection<ProjectItem> GetItems (string itemType)
307                 {
308                         throw new NotImplementedException ();
309                 }
310
311                 public ICollection<ProjectItem> GetItemsByEvaluatedInclude (string evaluatedInclude)
312                 {
313                         throw new NotImplementedException ();
314                 }
315
316                 public IEnumerable<ProjectElement> GetLogicalProject ()
317                 {
318                         throw new NotImplementedException ();
319                 }
320
321                 public static string GetMetadataValueEscaped (ProjectMetadata metadatum)
322                 {
323                         throw new NotImplementedException ();
324                 }
325
326                 public static string GetMetadataValueEscaped (ProjectItem item, string name)
327                 {
328                         throw new NotImplementedException ();
329                 }
330
331                 public static string GetMetadataValueEscaped (ProjectItemDefinition item, string name)
332                 {
333                         throw new NotImplementedException ();
334                 }
335
336                 public string GetPropertyValue (string name)
337                 {
338                         var prop = GetProperty (name);
339                         return prop != null ? prop.EvaluatedValue : string.Empty;
340                 }
341
342                 public static string GetPropertyValueEscaped (ProjectProperty property)
343                 {
344                         return property.EvaluatedValue;
345                 }
346
347                 public ProjectProperty GetProperty (string name)
348                 {
349                         return properties.FirstOrDefault (p => p.Name == name);
350                 }
351
352                 public void MarkDirty ()
353                 {
354                         throw new NotImplementedException ();
355                 }
356
357                 public void ReevaluateIfNecessary ()
358                 {
359                         throw new NotImplementedException ();
360                 }
361
362                 public bool RemoveGlobalProperty (string name)
363                 {
364                         throw new NotImplementedException ();
365                 }
366
367                 public bool RemoveItem (ProjectItem item)
368                 {
369                         throw new NotImplementedException ();
370                 }
371
372                 public bool RemoveProperty (ProjectProperty property)
373                 {
374                         var removed = properties.FirstOrDefault (p => p.Name == property.Name);
375                         if (removed == null)
376                                 return false;
377                         properties.Remove (removed);
378                         return true;
379                 }
380
381                 public void Save ()
382                 {
383                         Xml.Save ();
384                 }
385
386                 public void Save (TextWriter writer)
387                 {
388                         Xml.Save (writer);
389                 }
390
391                 public void Save (string path)
392                 {
393                         Save (path, Encoding.Default);
394                 }
395
396                 public void Save (Encoding encoding)
397                 {
398                         Save (FullPath, encoding);
399                 }
400
401                 public void Save (string path, Encoding encoding)
402                 {
403                         using (var writer = new StreamWriter (path, false, encoding))
404                                 Save (writer);
405                 }
406
407                 public void SaveLogicalProject (TextWriter writer)
408                 {
409                         throw new NotImplementedException ();
410                 }
411
412                 public bool SetGlobalProperty (string name, string escapedValue)
413                 {
414                         throw new NotImplementedException ();
415                 }
416
417                 public ProjectProperty SetProperty (string name, string unevaluatedValue)
418                 {
419                         var p = new ManuallyAddedProjectProperty (this, name, unevaluatedValue);
420                         properties.Add (p);
421                         return p;
422                 }
423
424                 public ICollection<ProjectMetadata> AllEvaluatedItemDefinitionMetadata { get; private set; }
425
426                 public ICollection<ProjectItem> AllEvaluatedItems { get; private set; }
427
428                 public ICollection<ProjectProperty> AllEvaluatedProperties { get; private set; }
429
430                 public IDictionary<string, List<string>> ConditionedProperties {
431                         get {
432                                 // this property returns different instances every time.
433                                 var dic = new Dictionary<string, List<string>> ();
434                                 
435                                 // but I dunno HOW this evaluates
436                                 
437                                 throw new NotImplementedException ();
438                         }
439                 }
440
441                 public string DirectoryPath {
442                         get { return dir_path; }
443                 }
444
445                 public bool DisableMarkDirty { get; set; }
446
447                 public int EvaluationCounter {
448                         get { throw new NotImplementedException (); }
449                 }
450
451                 public string FullPath {
452                         get { return Xml.FullPath; }
453                         set { Xml.FullPath = value; }
454                 }
455
456                 public IList<ResolvedImport> Imports {
457                         get { throw new NotImplementedException (); }
458                 }
459
460                 public IList<ResolvedImport> ImportsIncludingDuplicates {
461                         get { return raw_imports; }
462                 }
463
464                 public bool IsBuildEnabled {
465                         get { return ProjectCollection.IsBuildEnabled; }
466                 }
467
468                 public bool IsDirty {
469                         get { throw new NotImplementedException (); }
470                 }
471
472                 public IDictionary<string, ProjectItemDefinition> ItemDefinitions {
473                         get { return item_definitions; }
474                 }
475
476                 public ICollection<ProjectItem> Items {
477                         get { throw new NotImplementedException (); }
478                 }
479
480                 public ICollection<ProjectItem> ItemsIgnoringCondition {
481                         get { return raw_items; }
482                 }
483
484                 public ICollection<string> ItemTypes {
485                         get { return item_types; }
486                 }
487
488                 public ICollection<ProjectProperty> Properties {
489                         get { return properties; }
490                 }
491
492                 public bool SkipEvaluation { get; set; }
493
494                 #if NET_4_5
495                 public
496                 #else
497                 internal
498                 #endif
499                 IDictionary<string, ProjectTargetInstance> Targets {
500                         get { return targets; }
501                 }
502         }
503 }