X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FMicrosoft.Build.Engine%2FMicrosoft.Build.BuildEngine%2FBuildItem.cs;h=45792185cb879213d6d91e197977b0e4ac36be8b;hb=8657a158fb471d08555609f52ebb4e1b0d7d298a;hp=2d8ed69dec63ee3a8f64f1f7183392d03bfe12ed;hpb=3f72f57672d0ab615c0953063d79b836ceb7c719;p=mono.git diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs index 2d8ed69dec6..45792185cb8 100644 --- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs +++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs @@ -29,6 +29,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Text; @@ -40,57 +41,80 @@ using Mono.XBuild.Utilities; namespace Microsoft.Build.BuildEngine { public class BuildItem { + List child_items; XmlElement itemElement; string finalItemSpec; bool isImported; + string itemInclude; string name; - BuildItemGroup parentItemGroup; - string recursiveDir; + BuildItemGroup parent_item_group; + BuildItem parent_item; + //string recursiveDir; IDictionary evaluatedMetadata; IDictionary unevaluatedMetadata; - private BuildItem () + BuildItem () { } public BuildItem (string itemName, ITaskItem taskItem) { + if (taskItem == null) + throw new ArgumentNullException ("taskItem"); + this.name = itemName; this.finalItemSpec = taskItem.ItemSpec; + this.itemInclude = Utilities.Escape (taskItem.ItemSpec); this.evaluatedMetadata = (Hashtable) taskItem.CloneCustomMetadata (); this.unevaluatedMetadata = (Hashtable) taskItem.CloneCustomMetadata (); } public BuildItem (string itemName, string itemInclude) { - this.name = itemName; - this.finalItemSpec = itemInclude; - this.unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); - this.evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); + if (itemInclude == null) + throw new ArgumentNullException ("itemInclude"); + if (itemInclude == String.Empty) + throw new ArgumentException ("Parameter \"itemInclude\" cannot have zero length."); + + name = itemName; + finalItemSpec = itemInclude; + this.itemInclude = itemInclude; + unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); + evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); } - + internal BuildItem (XmlElement itemElement, BuildItemGroup parentItemGroup) { - this.isImported = false; - this.unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); - this.evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); - this.parentItemGroup = parentItemGroup; - BindToXml (itemElement); + child_items = new List (); + isImported = parentItemGroup.IsImported; + unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); + evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (); + this.parent_item_group = parentItemGroup; + + this.itemElement = itemElement; + + if (Include == String.Empty) + throw new InvalidProjectFileException (String.Format ("The required attribute \"Include\" is missing from element <{0}>.", Name)); } - private BuildItem (BuildItem parent) + BuildItem (BuildItem parent) { - this.isImported = parent.isImported; - this.name = parent.name; - this.parentItemGroup = parent.parentItemGroup; - this.unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (parent.unevaluatedMetadata); - this.evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (parent.evaluatedMetadata); + isImported = parent.isImported; + name = parent.Name; + parent_item = parent; + parent_item.child_items.Add (this); + parent_item_group = parent.parent_item_group; + unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (parent.unevaluatedMetadata); + evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (parent.evaluatedMetadata); } public void CopyCustomMetadataTo (BuildItem destinationItem) { + if (destinationItem == null) + throw new ArgumentNullException ("destinationItem"); + foreach (DictionaryEntry de in unevaluatedMetadata) - destinationItem.SetMetadata ((string) de.Key, (string) de.Value); + destinationItem.AddMetadata ((string) de.Key, (string) de.Value); } [MonoTODO] @@ -101,6 +125,11 @@ namespace Microsoft.Build.BuildEngine { public string GetEvaluatedMetadata (string metadataName) { + if (ReservedNameUtils.IsReservedMetadataName (metadataName)) { + string metadata = ReservedNameUtils.GetReservedMetadata (FinalItemSpec, metadataName); + return (metadataName.ToLower () == "fullpath") ? Utilities.Escape (metadata) : metadata; + } + if (evaluatedMetadata.Contains (metadataName)) return (string) evaluatedMetadata [metadataName]; else @@ -109,17 +138,21 @@ namespace Microsoft.Build.BuildEngine { public string GetMetadata (string metadataName) { - if (ReservedNameUtils.IsReservedMetadataName (metadataName)) - return ReservedNameUtils.GetReservedMetadata (FinalItemSpec, metadataName); - else if (evaluatedMetadata.Contains (metadataName) == true) - return (string) evaluatedMetadata [metadataName]; + if (ReservedNameUtils.IsReservedMetadataName (metadataName)) { + string metadata = ReservedNameUtils.GetReservedMetadata (FinalItemSpec, metadataName); + return (metadataName.ToLower () == "fullpath") ? Utilities.Escape (metadata) : metadata; + } else if (unevaluatedMetadata.Contains (metadataName)) + return (string) unevaluatedMetadata [metadataName]; else return String.Empty; } public bool HasMetadata (string metadataName) { - return evaluatedMetadata.Contains (metadataName); + if (ReservedNameUtils.IsReservedMetadataName (metadataName)) + return true; + else + return evaluatedMetadata.Contains (metadataName); } public void RemoveMetadata (string metadataName) @@ -128,13 +161,21 @@ namespace Microsoft.Build.BuildEngine { throw new ArgumentNullException ("metadataName"); if (ReservedNameUtils.IsReservedMetadataName (metadataName)) - throw new ArgumentException ("Can't remove reserved metadata."); - - if (evaluatedMetadata.Contains (metadataName)) - evaluatedMetadata.Remove (metadataName); + throw new ArgumentException (String.Format ("\"{0}\" is a reserved item meta-data, and cannot be modified or deleted.", + metadataName)); + + if (FromXml) { + if (unevaluatedMetadata.Contains (metadataName)) { + XmlNode node = itemElement [metadataName]; + itemElement.RemoveChild (node); + } + } else if (HasParentItem) { + if (parent_item.child_items.Count > 1) + SplitParentItem (); + parent_item.RemoveMetadata (metadataName); + } - if (unevaluatedMetadata.Contains (metadataName)) - unevaluatedMetadata.Remove (metadataName); + DeleteMetadata (metadataName); } public void SetMetadata (string metadataName, @@ -143,8 +184,6 @@ namespace Microsoft.Build.BuildEngine { SetMetadata (metadataName, metadataValue, false); } - // FIXME: don't use expression when we treat it as literal - [MonoTODO] public void SetMetadata (string metadataName, string metadataValue, bool treatMetadataValueAsLiteral) @@ -156,45 +195,77 @@ namespace Microsoft.Build.BuildEngine { throw new ArgumentNullException ("metadataValue"); if (ReservedNameUtils.IsReservedMetadataName (metadataName)) - throw new ArgumentException ("Can't modify reserved metadata."); - - RemoveMetadata (metadataName); + throw new ArgumentException (String.Format ("\"{0}\" is a reserved item meta-data, and cannot be modified or deleted.", + metadataName)); + + if (treatMetadataValueAsLiteral && !HasParentItem) + metadataValue = Utilities.Escape (metadataValue); + + if (FromXml) { + XmlElement element = itemElement [metadataName]; + if (element == null) { + element = itemElement.OwnerDocument.CreateElement (metadataName, Project.XmlNamespace); + element.InnerText = metadataValue; + itemElement.AppendChild (element); + } else + element.InnerText = metadataValue; + } else if (HasParentItem) { + if (parent_item.child_items.Count > 1) + SplitParentItem (); + parent_item.SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral); + } + if (FromXml || HasParentItem) { + parent_item_group.ParentProject.MarkProjectAsDirty (); + parent_item_group.ParentProject.NeedToReevaluate (); + } - unevaluatedMetadata.Add (metadataName, metadataValue); - OldExpression finalValue = new OldExpression (parentItemGroup.Project); - finalValue.ParseSource (metadataValue); - evaluatedMetadata.Add (metadataName, (string) finalValue.ConvertTo (typeof (string))); + DeleteMetadata (metadataName); + AddMetadata (metadataName, metadataValue); } - - private void BindToXml (XmlElement xmlElement) + + void AddMetadata (string name, string value) { - if (xmlElement == null) - throw new ArgumentNullException ("xmlElement"); - - this.itemElement = xmlElement; - this.name = xmlElement.Name; - - if (Include == String.Empty) - throw new InvalidProjectFileException ("Item must have Include attribute."); + if (parent_item_group != null) { + Expression e = new Expression (); + e.Parse (value, true); + evaluatedMetadata.Add (name, (string) e.ConvertTo (parent_item_group.ParentProject, typeof (string))); + } else + evaluatedMetadata.Add (name, Utilities.Unescape (value)); + + unevaluatedMetadata.Add (name, value); + } + + void DeleteMetadata (string name) + { + if (evaluatedMetadata.Contains (name)) + evaluatedMetadata.Remove (name); - foreach (XmlElement xe in xmlElement.ChildNodes) { - this.SetMetadata (xe.Name, xe.InnerText); - } + if (unevaluatedMetadata.Contains (name)) + unevaluatedMetadata.Remove (name); } - internal void Evaluate () + internal void Evaluate (Project project, bool evaluatedTo) { + // FIXME: maybe make Expression.ConvertTo (null, ...) work as Utilities.Unescape ()? + if (project == null) { + this.finalItemSpec = Utilities.Unescape (Include); + return; + } + + foreach (XmlElement xe in itemElement.ChildNodes) + AddMetadata (xe.Name, xe.InnerText); + DirectoryScanner directoryScanner; - OldExpression includeExpr, excludeExpr; + Expression includeExpr, excludeExpr; string includes, excludes; - includeExpr = new OldExpression (parentItemGroup.Project); - includeExpr.ParseSource (Include); - excludeExpr = new OldExpression (parentItemGroup.Project); - excludeExpr.ParseSource (Exclude); + includeExpr = new Expression (); + includeExpr.Parse (Include, true); + excludeExpr = new Expression (); + excludeExpr.Parse (Exclude, true); - includes = (string) includeExpr.ConvertTo (typeof (string)); - excludes = (string) excludeExpr.ConvertTo (typeof (string)); + includes = (string) includeExpr.ConvertTo (project, typeof (string)); + excludes = (string) excludeExpr.ConvertTo (project, typeof (string)); this.finalItemSpec = includes; @@ -202,48 +273,71 @@ namespace Microsoft.Build.BuildEngine { directoryScanner.Includes = includes; directoryScanner.Excludes = excludes; - if (parentItemGroup.Project.FullFileName != String.Empty) { - directoryScanner.BaseDirectory = new DirectoryInfo (Path.GetDirectoryName (parentItemGroup.Project.FullFileName)); - } else { + + if (project.FullFileName != String.Empty) + directoryScanner.BaseDirectory = new DirectoryInfo (Path.GetDirectoryName (project.FullFileName)); + else directoryScanner.BaseDirectory = new DirectoryInfo (Directory.GetCurrentDirectory ()); - } directoryScanner.Scan (); - foreach (string matchedFile in directoryScanner.MatchedFilenames) { - AddEvaluatedItem (matchedFile); - } + foreach (string matchedFile in directoryScanner.MatchedFilenames) + AddEvaluatedItem (project, evaluatedTo, matchedFile); } - private void AddEvaluatedItem (string itemSpec) + void AddEvaluatedItem (Project project, bool evaluatedTo, string itemSpec) { - Project project = this.parentItemGroup.Project; - + BuildItemGroup big; BuildItem bi = new BuildItem (this); bi.finalItemSpec = itemSpec; - project.EvaluatedItems.AddItem (bi); - if (project.EvaluatedItemsByName.Contains (bi.name) == false) { - BuildItemGroup big = new BuildItemGroup (null, project); - project.EvaluatedItemsByName.Add (bi.name, big); + + if (evaluatedTo) { + project.EvaluatedItems.AddItem (bi); + + if (!project.EvaluatedItemsByName.ContainsKey (bi.Name)) { + big = new BuildItemGroup (null, project, null, true); + project.EvaluatedItemsByName.Add (bi.Name, big); + } else { + big = project.EvaluatedItemsByName [bi.Name]; + } + big.AddItem (bi); + } + + if (!project.EvaluatedItemsByNameIgnoringCondition.ContainsKey (bi.Name)) { + big = new BuildItemGroup (null, project, null, true); + project.EvaluatedItemsByNameIgnoringCondition.Add (bi.Name, big); } else { - ((BuildItemGroup) project.EvaluatedItemsByName [bi.name]).AddItem (bi); + big = project.EvaluatedItemsByNameIgnoringCondition [bi.Name]; } + + big.AddItem (bi); } - internal string ConvertToString (OldExpression transform) + internal string ConvertToString (Expression transform) { return GetItemSpecFromTransform (transform); } - internal ITaskItem ConvertToITaskItem (OldExpression transform) + internal ITaskItem ConvertToITaskItem (Expression transform) { TaskItem taskItem; taskItem = new TaskItem (GetItemSpecFromTransform (transform), evaluatedMetadata); return taskItem; } - private string GetItemSpecFromTransform (OldExpression transform) + internal void Detach () + { + if (FromXml) + itemElement.ParentNode.RemoveChild (itemElement); + else if (HasParentItem) { + if (parent_item.child_items.Count > 1) + SplitParentItem (); + parent_item.Detach (); + } + } + + string GetItemSpecFromTransform (Expression transform) { StringBuilder sb; @@ -255,9 +349,9 @@ namespace Microsoft.Build.BuildEngine { if (o is string) { sb.Append ((string)o); } else if (o is PropertyReference) { - sb.Append (((PropertyReference)o).ConvertToString ()); + sb.Append (((PropertyReference)o).ConvertToString (parent_item_group.ParentProject)); } else if (o is ItemReference) { - sb.Append (((ItemReference)o).ConvertToString ()); + sb.Append (((ItemReference)o).ConvertToString (parent_item_group.ParentProject)); } else if (o is MetadataReference) { sb.Append (GetMetadata (((MetadataReference)o).MetadataName)); } @@ -266,14 +360,68 @@ namespace Microsoft.Build.BuildEngine { } } + void SplitParentItem () + { + BuildItem parent = parent_item; + List list = new List (); + XmlElement insertAfter = parent.itemElement; + foreach (BuildItem bi in parent.child_items) { + BuildItem added = InsertElementAfter (parent, bi, insertAfter); + insertAfter = added.itemElement; + list.Add (added); + } + parent.parent_item_group.ReplaceWith (parent, list); + parent.itemElement.ParentNode.RemoveChild (parent.itemElement); + } + + static BuildItem InsertElementAfter (BuildItem parent, BuildItem child, XmlElement insertAfter) + { + BuildItem newParent; + + XmlDocument doc = parent.itemElement.OwnerDocument; + XmlElement newElement = doc.CreateElement (child.Name, Project.XmlNamespace); + newElement.SetAttribute ("Include", child.FinalItemSpec); + if (parent.itemElement.HasAttribute ("Condition")) + newElement.SetAttribute ("Condition", parent.itemElement.GetAttribute ("Condition")); + foreach (XmlElement xe in parent.itemElement) + newElement.AppendChild (xe.Clone ()); + parent.itemElement.ParentNode.InsertAfter (newElement, insertAfter); + + newParent = new BuildItem (newElement, parent.parent_item_group); + newParent.child_items.Add (child); + child.parent_item = newParent; + + return newParent; + } + public string Condition { - get { return itemElement.GetAttribute ("Condition"); } - set { itemElement.SetAttribute ("Condition", value); } + get { + if (FromXml) + return itemElement.GetAttribute ("Condition"); + else + return String.Empty; + } + set { + if (FromXml) + itemElement.SetAttribute ("Condition", value); + else if (!HasParentItem) + throw new InvalidOperationException ("Cannot set a condition on an object not represented by an XML element in the project file."); + } } public string Exclude { - get { return itemElement.GetAttribute ("Exclude"); } - set { itemElement.SetAttribute ("Exclude", value); } + get { + if (FromXml) + return itemElement.GetAttribute ("Exclude"); + else + return String.Empty; + } + set { + if (FromXml) + itemElement.SetAttribute ("Exclude", value); + else + throw new InvalidOperationException ("Assigning the \"Exclude\" attribute of a virtual item is not allowed."); + } } public string FinalItemSpec { @@ -281,8 +429,24 @@ namespace Microsoft.Build.BuildEngine { } public string Include { - get { return itemElement.GetAttribute ("Include"); } - set { itemElement.SetAttribute ("Include", value); } + get { + if (FromXml) + return itemElement.GetAttribute ("Include"); + else if (HasParentItem) + return parent_item.Include; + else + return itemInclude; + } + set { + if (FromXml) + itemElement.SetAttribute ("Include", value); + else if (HasParentItem) { + if (parent_item.child_items.Count > 1) + SplitParentItem (); + parent_item.Include = value; + } else + itemInclude = value; + } } public bool IsImported { @@ -290,14 +454,47 @@ namespace Microsoft.Build.BuildEngine { } public string Name { - get { return name; } - set { name = value; } + get { + if (FromXml) + return itemElement.Name; + else if (HasParentItem) + return parent_item.Name; + else + return name; + } + set { + if (FromXml) { + XmlElement newElement = itemElement.OwnerDocument.CreateElement (value, Project.XmlNamespace); + newElement.SetAttribute ("Include", itemElement.GetAttribute ("Include")); + newElement.SetAttribute ("Condition", itemElement.GetAttribute ("Condition")); + foreach (XmlElement xe in itemElement) + newElement.AppendChild (xe.Clone ()); + itemElement.ParentNode.ReplaceChild (newElement, itemElement); + itemElement = newElement; + } else if (HasParentItem) { + if (parent_item.child_items.Count > 1) + SplitParentItem (); + parent_item.Name = value; + } else + name = value; + } } internal bool FromXml { - get { - return itemElement != null; - } + get { return itemElement != null; } + } + + internal bool HasParentItem { + get { return parent_item != null; } + } + + internal BuildItem ParentItem { + get { return parent_item; } + } + + internal BuildItemGroup ParentItemGroup { + get { return parent_item_group; } + set { parent_item_group = value; } } } }