Merge pull request #1033 from godFather89/master
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / BuildProperty.cs
1 //
2 // BuildProperty.cs: Represents a property
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //   Ankit Jain (jankit@novell.com)
7 // 
8 // (C) 2005 Marek Sieradzki
9 // Copyright 2009 Novell, Inc (http://www.novell.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 using System;
31 using System.Text;
32 using System.Xml;
33 using System.Collections.Generic;
34
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
37 using Mono.XBuild.Utilities;
38
39 namespace Microsoft.Build.BuildEngine {
40         public class BuildProperty {
41         
42                 XmlElement      propertyElement;
43                 string          finalValue;
44                 bool            isImported;
45                 string          value;
46                 string          name;
47                 Project         parentProject;
48                 PropertyType    propertyType;
49                 bool            converting;
50
51                 BuildProperty ()
52                 {
53                 }
54
55                 public BuildProperty (string propertyName, string propertyValue)
56                         : this (propertyName, propertyValue, PropertyType.Normal)
57                 {
58                         if (propertyName == null)
59                                 throw new ArgumentNullException ("propertyName");
60                         if (propertyValue == null)
61                                 throw new ArgumentNullException ("propertyValue");
62                 }
63
64                 internal BuildProperty (string propertyName,
65                                 string propertyValue, PropertyType propertyType)
66                 {
67                         this.name = propertyName;
68                         this.value = propertyValue;
69                         this.finalValue = propertyValue;
70                         this.propertyType = propertyType;
71                         this.isImported = false;
72                 }
73
74                 internal BuildProperty (Project parentProject, XmlElement propertyElement)
75                 {
76                         if (propertyElement == null)
77                                 throw new ArgumentNullException ("propertyElement");
78
79                         this.propertyElement = propertyElement;
80                         this.propertyType = PropertyType.Normal;
81                         this.parentProject = parentProject;
82                         this.name = propertyElement.Name;
83                         this.value = MSBuildUtils.UnescapeFromXml (propertyElement.InnerXml);
84                         this.isImported = false;
85                 }
86
87                 [MonoTODO]
88                 public BuildProperty Clone (bool deepClone)
89                 {
90                         if (deepClone) {
91                                 if (FromXml) 
92                                         throw new NotImplementedException ();
93                                 else
94                                         return (BuildProperty) this.MemberwiseClone ();
95                         } else {
96                                 if (FromXml)
97                                         throw new NotImplementedException ();
98                                 else
99                                         throw new InvalidOperationException ("A shallow clone of this object cannot be created.");
100                         }
101                 }
102
103                 public static explicit operator string (BuildProperty propertyToCast)
104                 {
105                         if (propertyToCast == null)
106                                 return String.Empty;
107                         else
108                                 return propertyToCast.ToString ();
109                 }
110
111                 public override string ToString ()
112                 {
113                         if (finalValue != null)
114                                 return finalValue;
115                         else
116                                 return Value;
117                 }
118
119                 internal void Evaluate ()
120                 {
121                         BuildProperty evaluated = new BuildProperty (Name, Value);
122
123                         // In evaluate phase, properties are not expanded
124                         evaluated.finalValue = Expression.ParseAs<string> (Value, ParseOptions.None, 
125                                 parentProject, ExpressionOptions.DoNotExpandItemRefs);
126
127                         parentProject.EvaluatedProperties.AddProperty (evaluated);
128                 }
129
130                 // during property's eval phase, this is never reached, as PropertyReference
131                 // handles the eval case
132                 //
133                 // during item's eval phase, we have expand: true, that's what we
134                 // do here..
135                 //
136                 // during non-eval, expand: true
137                 // So, its always true here
138                 internal string ConvertToString (Project project, ExpressionOptions options)
139                 {
140                         if (converting) {
141                                 // found ref to @this while trying to ConvertToString
142                                 // for @this!
143                                 return FinalValue;
144                         }
145
146                         converting = true;
147                         try {
148                                 Expression exp = new Expression ();
149
150                                 // in non-evaluation phase, properties are always expanded
151                                 exp.Parse (FinalValue, options == ExpressionOptions.ExpandItemRefs ?
152                                                         ParseOptions.AllowItems : ParseOptions.None);
153                                 return (string) exp.ConvertTo (project, typeof (string), options);
154                         } finally {
155                                 converting = false;
156                         }
157                 }
158
159                 internal ITaskItem[] ConvertToITaskItemArray (Project project, ExpressionOptions options)
160                 {
161                         if (converting) {
162                                 // found ref to @this while trying to ConvertToITaskItemArray
163                                 // for @this!
164                                 ITaskItem []items = new ITaskItem [1];
165                                 items [0] = new TaskItem (FinalValue);
166                                 return items;
167                         }
168
169                         converting = true;
170                         try {
171                                 Expression exp = new Expression ();
172
173                                 // in non-evaluation phase, properties are always expanded
174                                 exp.Parse (FinalValue, ParseOptions.Split | (options == ExpressionOptions.ExpandItemRefs ?
175                                                         ParseOptions.AllowItems : ParseOptions.None));
176                                 return (ITaskItem[]) exp.ConvertTo (project, typeof (ITaskItem[]), options);
177                         } finally {
178                                 converting = false;
179                         }
180                 }
181
182                 internal bool FromXml {
183                         get {
184                                 return propertyElement != null;
185                         }
186                 }
187         
188                 public string Condition {
189                         get {
190                                 if (FromXml)
191                                         return propertyElement.GetAttribute ("Condition");
192                                 else
193                                         return String.Empty;
194                         }
195                         set {
196                                 if (FromXml)
197                                         propertyElement.SetAttribute ("Condition", value);
198                                 else
199                                         throw new InvalidOperationException ("Cannot set a condition on an object not represented by an XML element in the project file.");
200                         }
201                 }
202
203                 public string FinalValue {
204                         get {
205                                 if (finalValue == null)
206                                         return this.@value;
207                                 else
208                                         return finalValue;
209                         }
210                 }
211                 
212                 public bool IsImported {
213                         get { return isImported; }
214                 }
215
216                 public string Name {
217                         get { return name; }
218                 }
219
220                 public string Value {
221                         get {
222                                 return value;
223                         }
224                         set {
225                                 this.@value = value;
226                                 if (FromXml) {
227                                         propertyElement.InnerXml = value;
228                                 } else {
229                                         finalValue = value;
230                                 }
231                         }
232                 }
233
234                 internal PropertyType PropertyType {
235                         get {
236                                 return propertyType;
237                         }
238                 }
239
240                 internal XmlElement XmlElement {
241                         get { return propertyElement; }
242                 }
243
244                 internal IEnumerable<string> GetAttributes ()
245                 {
246                         if (!FromXml)
247                                 yield break;
248                         foreach (XmlAttribute attr in propertyElement.Attributes)
249                                 yield return attr.Value;
250                 }
251         }
252
253         internal enum PropertyType {
254                 Reserved,
255                 Global,
256                 Normal,
257                 Environment
258         }
259 }