using System;
using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
namespace Microsoft.Build.BuildEngine {
public class BuildItem {
+ List<BuildItem> 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<BuildItem> ();
+ 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]
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
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)
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,
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)
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;
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;
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));
}
}
}
+ void SplitParentItem ()
+ {
+ BuildItem parent = parent_item;
+ List <BuildItem> list = new List <BuildItem> ();
+ 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 {
}
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 {
}
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; }
}
}
}