implement Project.RemoveProperty() and ProjectProperty.Predecessor (i.e. property...
[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                         }
176                 }
177
178                 public ICollection<ProjectItem> GetItemsIgnoringCondition (string itemType)
179                 {
180                         return new CollectionFromEnumerable<ProjectItem> (
181                                 new FilteredEnumerable<ProjectItemElement> (Xml.Items).
182                                 Where (p => p.ItemType.Equals (itemType, StringComparison.OrdinalIgnoreCase)).
183                                 Select (p => new ProjectItem (p)));
184                 }
185
186                 public void RemoveItems (IEnumerable<ProjectItem> items)
187                 {
188                         var removal = new List<ProjectItem> (items);
189                         foreach (var item in removal) {
190                                 var parent = item.Xml.Parent;
191                                 parent.RemoveChild (item.Xml);
192                                 if (parent.Count == 0)
193                                         parent.Parent.RemoveChild (parent);
194                         }
195                 }
196
197                 static readonly Dictionary<string, string> empty_metadata = new Dictionary<string, string> ();
198
199                 public IList<ProjectItem> AddItem (string itemType, string unevaluatedInclude)
200                 {
201                         return AddItem (itemType, unevaluatedInclude, empty_metadata);
202                 }
203
204                 public IList<ProjectItem> AddItem (string itemType, string unevaluatedInclude,
205                                 IEnumerable<KeyValuePair<string, string>> metadata)
206                 {
207                         // FIXME: needs several check that AddItemFast() does not process (see MSDN for details).
208
209                         return AddItemFast (itemType, unevaluatedInclude, metadata);
210                 }
211
212                 public IList<ProjectItem> AddItemFast (string itemType, string unevaluatedInclude)
213                 {
214                         return AddItemFast (itemType, unevaluatedInclude, empty_metadata);
215                 }
216
217                 public IList<ProjectItem> AddItemFast (string itemType, string unevaluatedInclude,
218                                                                      IEnumerable<KeyValuePair<string, string>> metadata)
219                 {
220                         throw new NotImplementedException ();
221                 }
222
223                 public bool Build ()
224                 {
225                         return Build (Xml.DefaultTargets.Split (';'));
226                 }
227
228                 public bool Build (IEnumerable<ILogger> loggers)
229                 {
230                         return Build (Xml.DefaultTargets.Split (';'), loggers);
231                 }
232
233                 public bool Build (string target)
234                 {
235                         return string.IsNullOrWhiteSpace (target) ? Build () : Build (new string [] {target});
236                 }
237
238                 public bool Build (string[] targets)
239                 {
240                         return Build (targets, new ILogger [0]);
241                 }
242
243                 public bool Build (ILogger logger)
244                 {
245                         return Build (Xml.DefaultTargets.Split (';'), new ILogger [] {logger});
246                 }
247
248                 public bool Build (string[] targets, IEnumerable<ILogger> loggers)
249                 {
250                         return Build (targets, loggers, new ForwardingLoggerRecord [0]);
251                 }
252
253                 public bool Build (IEnumerable<ILogger> loggers, IEnumerable<ForwardingLoggerRecord> remoteLoggers)
254                 {
255                         return Build (Xml.DefaultTargets.Split (';'), loggers, remoteLoggers);
256                 }
257
258                 public bool Build (string target, IEnumerable<ILogger> loggers)
259                 {
260                         return Build (new string [] { target }, loggers);
261                 }
262
263                 public bool Build (string[] targets, IEnumerable<ILogger> loggers, IEnumerable<ForwardingLoggerRecord> remoteLoggers)
264                 {
265                         // Unlike ProjectInstance.Build(), there is no place to fill outputs by targets, so ignore them
266                         // (i.e. we don't use the overload with output).
267                         //
268                         // This does not check FullPath, so don't call GetProjectInstanceForBuild() directly.
269                         return new BuildManager ().GetProjectInstanceForBuildInternal (this).Build (targets, loggers, remoteLoggers);
270                 }
271
272                 public bool Build (string target, IEnumerable<ILogger> loggers, IEnumerable<ForwardingLoggerRecord> remoteLoggers)
273                 {
274                         return Build (new string [] { target }, loggers, remoteLoggers);
275                 }
276
277                 public ProjectInstance CreateProjectInstance ()
278                 {
279                         var ret = new ProjectInstance (Xml, GlobalProperties, ToolsVersion, ProjectCollection);
280                         // FIXME: maybe fill other properties to the result.
281                         return ret;
282                 }
283
284                 public string ExpandString (string unexpandedValue)
285                 {
286                         throw new NotImplementedException ();
287                 }
288
289                 public static string GetEvaluatedItemIncludeEscaped (ProjectItem item)
290                 {
291                         throw new NotImplementedException ();
292                 }
293
294                 public static string GetEvaluatedItemIncludeEscaped (ProjectItemDefinition item)
295                 {
296                         throw new NotImplementedException ();
297                 }
298
299                 public ICollection<ProjectItem> GetItems (string itemType)
300                 {
301                         throw new NotImplementedException ();
302                 }
303
304                 public ICollection<ProjectItem> GetItemsByEvaluatedInclude (string evaluatedInclude)
305                 {
306                         throw new NotImplementedException ();
307                 }
308
309                 public IEnumerable<ProjectElement> GetLogicalProject ()
310                 {
311                         throw new NotImplementedException ();
312                 }
313
314                 public static string GetMetadataValueEscaped (ProjectMetadata metadatum)
315                 {
316                         throw new NotImplementedException ();
317                 }
318
319                 public static string GetMetadataValueEscaped (ProjectItem item, string name)
320                 {
321                         throw new NotImplementedException ();
322                 }
323
324                 public static string GetMetadataValueEscaped (ProjectItemDefinition item, string name)
325                 {
326                         throw new NotImplementedException ();
327                 }
328
329                 public string GetPropertyValue (string name)
330                 {
331                         var prop = GetProperty (name);
332                         return prop != null ? prop.EvaluatedValue : string.Empty;
333                 }
334
335                 public static string GetPropertyValueEscaped (ProjectProperty property)
336                 {
337                         return property.EvaluatedValue;
338                 }
339
340                 public ProjectProperty GetProperty (string name)
341                 {
342                         throw new NotImplementedException ();
343                 }
344
345                 public void MarkDirty ()
346                 {
347                         throw new NotImplementedException ();
348                 }
349
350                 public void ReevaluateIfNecessary ()
351                 {
352                         throw new NotImplementedException ();
353                 }
354
355                 public bool RemoveGlobalProperty (string name)
356                 {
357                         throw new NotImplementedException ();
358                 }
359
360                 public bool RemoveItem (ProjectItem item)
361                 {
362                         throw new NotImplementedException ();
363                 }
364
365                 public bool RemoveProperty (ProjectProperty property)
366                 {
367                         var removed = properties.FirstOrDefault (p => p.Name == property.Name);
368                         if (removed == null)
369                                 return false;
370                         properties.Remove (removed);
371                         return true;
372                 }
373
374                 public void Save ()
375                 {
376                         Xml.Save ();
377                 }
378
379                 public void Save (TextWriter writer)
380                 {
381                         Xml.Save (writer);
382                 }
383
384                 public void Save (string path)
385                 {
386                         Save (path, Encoding.Default);
387                 }
388
389                 public void Save (Encoding encoding)
390                 {
391                         Save (FullPath, encoding);
392                 }
393
394                 public void Save (string path, Encoding encoding)
395                 {
396                         using (var writer = new StreamWriter (path, false, encoding))
397                                 Save (writer);
398                 }
399
400                 public void SaveLogicalProject (TextWriter writer)
401                 {
402                         throw new NotImplementedException ();
403                 }
404
405                 public bool SetGlobalProperty (string name, string escapedValue)
406                 {
407                         throw new NotImplementedException ();
408                 }
409
410                 public ProjectProperty SetProperty (string name, string unevaluatedValue)
411                 {
412                         throw new NotImplementedException ();
413                 }
414
415                 public ICollection<ProjectMetadata> AllEvaluatedItemDefinitionMetadata { get; private set; }
416
417                 public ICollection<ProjectItem> AllEvaluatedItems { get; private set; }
418
419                 public ICollection<ProjectProperty> AllEvaluatedProperties { get; private set; }
420
421                 public IDictionary<string, List<string>> ConditionedProperties {
422                         get {
423                                 // this property returns different instances every time.
424                                 var dic = new Dictionary<string, List<string>> ();
425                                 
426                                 // but I dunno HOW this evaluates
427                                 
428                                 throw new NotImplementedException ();
429                         }
430                 }
431
432                 public string DirectoryPath {
433                         get { return dir_path; }
434                 }
435
436                 public bool DisableMarkDirty { get; set; }
437
438                 public int EvaluationCounter {
439                         get { throw new NotImplementedException (); }
440                 }
441
442                 public string FullPath {
443                         get { return Xml.FullPath; }
444                         set { Xml.FullPath = value; }
445                 }
446
447                 public IList<ResolvedImport> Imports {
448                         get { throw new NotImplementedException (); }
449                 }
450
451                 public IList<ResolvedImport> ImportsIncludingDuplicates {
452                         get { return raw_imports; }
453                 }
454
455                 public bool IsBuildEnabled {
456                         get { throw new NotImplementedException (); }
457                 }
458
459                 public bool IsDirty {
460                         get { throw new NotImplementedException (); }
461                 }
462
463                 public IDictionary<string, ProjectItemDefinition> ItemDefinitions {
464                         get { return item_definitions; }
465                 }
466
467                 public ICollection<ProjectItem> Items {
468                         get { throw new NotImplementedException (); }
469                 }
470
471                 public ICollection<ProjectItem> ItemsIgnoringCondition {
472                         get { return raw_items; }
473                 }
474
475                 public ICollection<string> ItemTypes {
476                         get { return item_types; }
477                 }
478
479                 public ICollection<ProjectProperty> Properties {
480                         get { return properties; }
481                 }
482
483                 public bool SkipEvaluation { get; set; }
484
485                 #if NET_4_5
486                 public
487                 #else
488                 internal
489                 #endif
490                 IDictionary<string, ProjectTargetInstance> Targets {
491                         get { return targets; }
492                 }
493         }
494 }