Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Evaluation / ProjectProperty.cs
1 // ProjectProperty.cs
2 //
3 // Author:
4 //   Rolf Bjarne Kvinge (rolf@xamarin.com)
5 //   Atsushi Enomoto (atsushi@xamarin.com)
6 //
7 // Copyright (C) 2011,2013 Xamarin Inc.
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28
29 using System;
30 using System.Linq;
31 using Microsoft.Build.Construction;
32 using Microsoft.Build.Internal;
33 using System.Collections.Generic;
34 using System.Reflection;
35 using System.IO;
36
37 namespace Microsoft.Build.Evaluation
38 {
39         // In .NET 4.0 MSDN says it is non-abstract, but some of those
40         // members are abstract and had been there since 4.0.
41         // I take this as doc bug, as non-abstract to abstract is a
42         // breaking change and I'd rather believe API designer's sanity.
43         public abstract class ProjectProperty
44         {
45                 internal ProjectProperty (Project project) // hide default ctor
46                 {
47                         Project = project;
48                 }
49
50                 public string EvaluatedValue {
51                         get { return InternalEvaluatedValue; }
52                 }
53
54                 public abstract bool IsEnvironmentProperty { get; }
55
56                 public abstract bool IsGlobalProperty { get; }
57
58                 [MonoTODO]
59                 public abstract bool IsImported { get; }
60
61                 public abstract bool IsReservedProperty { get; }
62
63                 internal virtual bool IsWellKnownProperty {
64                         get { return false; }
65                 }
66
67                 public abstract string Name { get; }
68
69                 public abstract ProjectProperty Predecessor { get; }
70
71                 public Project Project { get; private set; }
72
73                 public abstract string UnevaluatedValue { get; set; }
74
75                 public abstract ProjectPropertyElement Xml { get; }
76                 
77                 internal abstract string InternalEvaluatedValue { get; }
78         }
79
80         // copy from MS.Build.Engine/BuildProperty.cs
81         internal enum PropertyType {
82                 Reserved,
83                 Global,
84                 Normal,
85                 Environment
86         }
87         
88         internal abstract class BaseProjectProperty : ProjectProperty
89         {
90                 public BaseProjectProperty (Project project, PropertyType propertyType, string name)
91                         : base (project)
92                 {
93                         property_type = propertyType;
94                         this.name = name;
95                         predecessor = project.Properties.FirstOrDefault (p => p.Name.Equals (name, StringComparison.OrdinalIgnoreCase));
96                         if (predecessor != null)
97                                 project.RemoveProperty (predecessor);
98                 }
99                 
100                 PropertyType property_type;
101                 
102                 readonly string name;
103                 public override string Name {
104                         get { return name; }
105                 }
106                 
107                 public override bool IsEnvironmentProperty {
108                         get { return property_type == PropertyType.Environment; }
109                 }
110                 public override bool IsGlobalProperty {
111                         get { return property_type == PropertyType.Global; }
112                 }
113                 public override bool IsImported {
114                         get { return false; }
115                 }
116                 public override bool IsReservedProperty {
117                         get { return property_type == PropertyType.Reserved; }
118                 }
119                 readonly ProjectProperty predecessor; 
120                 public override ProjectProperty Predecessor {
121                         get { return predecessor; }
122                 }
123         }
124         
125         internal abstract class ImmutableProjectProperty : BaseProjectProperty
126         {
127                 public ImmutableProjectProperty (Project project, PropertyType propertyType, string name)
128                         : base (project, propertyType, name)
129                 {
130                 }
131                 
132                 internal override string InternalEvaluatedValue {
133                         get { return UnevaluatedValue; }
134                 }
135         }
136         
137         internal abstract class MutableProjectProperty : BaseProjectProperty
138         {
139                 public MutableProjectProperty (Project project, PropertyType propertyType, string name)
140                         : base (project, propertyType, name)
141                 {
142                 }
143                 
144                 string evaluated_value; // see UpdateEvaluatedValue().
145                 internal void UpdateEvaluatedValue ()
146                 {
147                         evaluated_value = Project.ExpandString (UnevaluatedValue);
148                 }
149                 
150                 internal override string InternalEvaluatedValue {
151                         get { return evaluated_value; }
152                 }
153         }
154         
155         internal class XmlProjectProperty : MutableProjectProperty
156         {
157                 public XmlProjectProperty (Project project, ProjectPropertyElement xml, PropertyType propertyType, bool isImported)
158                         : base (project, propertyType, xml.Name)
159                 {
160                         this.xml = xml;
161                         this.is_imported = isImported;
162                         UpdateEvaluatedValue ();
163                 }
164                 
165                 readonly ProjectPropertyElement xml;
166                 readonly bool is_imported;
167                 
168                 public override bool IsImported {
169                         get { return is_imported; }
170                 }
171                 
172                 public override string UnevaluatedValue {
173                         get { return xml.Value; }
174                         set { xml.Value = value; }
175                 }
176                 
177                 public override ProjectPropertyElement Xml {
178                         get { return xml; }
179                 }
180         }
181         
182         internal class EnvironmentProjectProperty : ImmutableProjectProperty
183         {
184                 static string extensions_path;
185                 internal static string DefaultExtensionsPath {
186                         get {
187                                 if (extensions_path == null) {
188                                         // NOTE: code from mcs/tools/gacutil/driver.cs
189                                         PropertyInfo gac = typeof (System.Environment).GetProperty (
190                                                         "GacPath", BindingFlags.Static | BindingFlags.NonPublic);
191
192                                         if (gac != null) {
193                                                 MethodInfo get_gac = gac.GetGetMethod (true);
194                                                 string gac_path = (string) get_gac.Invoke (null, null);
195                                                 extensions_path = Path.GetFullPath (Path.Combine (
196                                                                         gac_path, Path.Combine ("..", "xbuild")));
197                                         }
198                                 }
199                                 return extensions_path;
200                         }
201                 }
202                 
203                 public EnvironmentProjectProperty (Project project, string name, string value, bool wellknown = false)
204                         : base (project, PropertyType.Environment, name)
205                 {
206                         this.value = value;
207                         this.wellknown = wellknown;
208                 }
209                 
210                 readonly string value;
211                 readonly bool wellknown;
212
213                 internal override bool IsWellKnownProperty {
214                         get { return wellknown; }
215                 }
216
217                 // It can override possible another environment vairable property BUT never gives Predecessor.
218                 public override ProjectProperty Predecessor {
219                         get { return null; }
220                 }
221                 
222                 public override string UnevaluatedValue {
223                         get { return value; }
224                         set { throw new InvalidOperationException (string.Format ("You cannot change value of environment property '{0}'.", Name)); }
225                 }
226                 public override ProjectPropertyElement Xml {
227                         get { return null; }
228                 }
229         }
230         
231         internal class GlobalProjectProperty : ImmutableProjectProperty
232         {
233                 public GlobalProjectProperty (Project project, string name, string value)
234                         : base (project, PropertyType.Global, name)
235                 {
236                         this.value = value;
237                 }
238                 
239                 readonly string value;
240                 
241                 public override string UnevaluatedValue {
242                         get { return value; }
243                         set { throw new InvalidOperationException (string.Format ("You cannot change value of global property '{0}'.", Name)); }
244                 }
245                 public override ProjectPropertyElement Xml {
246                         get { return null; }
247                 }
248         }
249         
250         internal class ManuallyAddedProjectProperty : MutableProjectProperty
251         {
252                 public ManuallyAddedProjectProperty (Project project, string name, string value)
253                         : base (project, PropertyType.Normal, name)
254                 {
255                         this.UnevaluatedValue = value;
256                 }
257                 
258                 public override string UnevaluatedValue { get; set; }
259                 
260                 public override ProjectPropertyElement Xml {
261                         get { return null; }
262                 }
263         }
264         
265         internal class ReservedProjectProperty : ImmutableProjectProperty
266         {
267                 public ReservedProjectProperty (Project project, string name, Func<string> value)
268                         : base (project, PropertyType.Reserved, name)
269                 {
270                         this.value = value;
271                 }
272
273                 // make sure it does not give access to any possible attempted overrrides.
274                 public override ProjectProperty Predecessor {
275                         get { return null; }
276                 }
277
278                 readonly Func<string> value;
279                 public override string UnevaluatedValue {
280                         get { return value (); }
281                         set { throw new InvalidOperationException (string.Format ("You cannot change value of reserved property '{0}'.", Name)); }
282                 }
283                 
284                 public override ProjectPropertyElement Xml {
285                         get { return null; }
286                 }
287         }
288 }