//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
+// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
{
parentProject = project;
}
+
+ // Rules (inferred) for property values incase of empty data
+ //
+ // Prop Type Argument Final Value Required
+ // string empty string null Yes/no
+ // string only whitespace @arg Yes/no
+ //
+ // string/
+ // ITaskItem[] empty/whitespace empty array Yes
+ //
+ // string/
+ // ITaskItem[] empty/whitespace null No
public void Prepare (ITask task, XmlElement taskElement,
IDictionary <string, string> parameters, Type taskType)
this.task = task;
this.taskElement = taskElement;
this.taskType = taskType;
- values = new Dictionary <string, object> ();
+ values = new Dictionary <string, object> (StringComparer.OrdinalIgnoreCase);
foreach (KeyValuePair <string, string> de in parameters) {
- currentProperty = taskType.GetProperty (de.Key);
+ currentProperty = taskType.GetProperty (de.Key, BindingFlags.Public | BindingFlags.Instance
+ | BindingFlags.IgnoreCase);
if (currentProperty == null)
throw new InvalidProjectFileException (String.Format ("Task does not have property \"{0}\" defined",
de.Key));
- value = GetObjectFromString (de.Value, currentProperty.PropertyType);
-
- if (value != null)
- values.Add (de.Key, value);
+ try {
+ if (TryGetObjectFromString (de.Value, currentProperty.PropertyType, out value))
+ values.Add (de.Key, value);
+ } catch (Exception e) {
+ throw new InvalidProjectFileException (String.Format (
+ "Error converting Property named '{0}' with value '{1}' to type {2}: {3}",
+ de.Key, de.Value, currentProperty.PropertyType, e.Message), e);
+ }
}
properties = taskType.GetProperties ();
foreach (PropertyInfo pi in properties) {
- if (pi.IsDefined (requiredAttribute, false) && values.ContainsKey (pi.Name) == false)
- throw new InvalidProjectFileException ("Required property not set.");
-
- if (values.ContainsKey (pi.Name))
- InitializeParameter (pi, values [pi.Name]);
+ bool is_required = pi.IsDefined (requiredAttribute, false);
+
+ if (is_required && values.ContainsKey (pi.Name) == false)
+ throw new InvalidProjectFileException (String.Format ("Required property '{0}' not set.",
+ pi.Name));
+
+ if (!values.ContainsKey (pi.Name))
+ continue;
+
+ Type prop_type = pi.PropertyType;
+ if (prop_type.IsArray)
+ prop_type = prop_type.GetElementType ();
+
+ // Valid data types: primitive types, DateTime, string and ITaskItem, and their arrays
+ if (!prop_type.IsPrimitive && prop_type != typeof (string) && prop_type != typeof (ITaskItem))
+ throw new InvalidProjectFileException (String.Format (
+ "{0} is not a supported type for properties for msbuild tasks.",
+ pi.PropertyType));
+
+ object val = values [pi.Name];
+ if (val == null && pi.PropertyType.IsArray && is_required) {
+ if (pi.PropertyType == typeof (ITaskItem[]))
+ val = new ITaskItem [0];
+ else if (pi.PropertyType == typeof (string[]))
+ val = new string [0];
+ }
+
+ InitializeParameter (pi, val);
}
}
object o;
foreach (XmlNode xmlNode in taskElement.ChildNodes) {
- if (xmlNode is XmlElement) {
- xmlElement = (XmlElement) xmlNode;
-
- if (xmlElement.Name != "Output")
- throw new InvalidProjectFileException ("Only Output elements can be Task's child nodes.");
- if (xmlElement.GetAttribute ("ItemName") != String.Empty && xmlElement.GetAttribute ("PropertyName") != String.Empty)
- throw new InvalidProjectFileException ("Only one of ItemName and ProperytyName attributes can be specified.");
- if (xmlElement.GetAttribute ("TaskParameter") == String.Empty)
- throw new InvalidProjectFileException ("TaskParameter attribute must be specified.");
-
- taskParameter = xmlElement.GetAttribute ("TaskParameter");
- itemName = xmlElement.GetAttribute ("ItemName");
- propertyName = xmlElement.GetAttribute ("PropertyName");
-
- propertyInfo = taskType.GetProperty (taskParameter);
- if (propertyInfo == null)
- throw new Exception ("Could not get property info.");
- if (propertyInfo.IsDefined (outputAttribute, false) == false)
- throw new Exception ("This is not output property.");
-
- o = propertyInfo.GetValue (task, null);
- if (o == null)
- continue;
+ if (!(xmlNode is XmlElement))
+ continue;
+
+ xmlElement = (XmlElement) xmlNode;
+
+ if (xmlElement.Name != "Output")
+ throw new InvalidProjectFileException ("Only Output elements can be Task's child nodes.");
+ if (xmlElement.GetAttribute ("ItemName") != String.Empty && xmlElement.GetAttribute ("PropertyName") != String.Empty)
+ throw new InvalidProjectFileException ("Only one of ItemName and PropertyName attributes can be specified.");
+ if (xmlElement.GetAttribute ("TaskParameter") == String.Empty)
+ throw new InvalidProjectFileException ("TaskParameter attribute must be specified.");
+
+ if (!ConditionParser.ParseAndEvaluate (xmlElement.GetAttribute ("Condition"), parentProject))
+ continue;
- if (itemName != String.Empty) {
- PublishItemGroup (propertyInfo, o, itemName);
- } else {
- PublishProperty (propertyInfo, o, propertyName);
- }
+ taskParameter = xmlElement.GetAttribute ("TaskParameter");
+ itemName = xmlElement.GetAttribute ("ItemName");
+ propertyName = xmlElement.GetAttribute ("PropertyName");
+
+ propertyInfo = taskType.GetProperty (taskParameter, BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.IgnoreCase);
+ if (propertyInfo == null)
+ throw new InvalidProjectFileException (String.Format (
+ "The parameter '{0}' was not found for the '{1}' task.", taskParameter, taskElement.Name));
+ if (!propertyInfo.IsDefined (outputAttribute, false))
+ throw new InvalidProjectFileException ("This is not output property.");
+
+ o = propertyInfo.GetValue (task, null);
+ if (itemName != String.Empty) {
+ PublishItemGroup (propertyInfo, o, itemName);
+ } else {
+ PublishProperty (propertyInfo, o, propertyName);
}
}
}
- private void InitializeParameter (PropertyInfo propertyInfo, object value)
+ void InitializeParameter (PropertyInfo propertyInfo, object value)
{
propertyInfo.SetValue (task, value, null);
}
- private void PublishItemGroup (PropertyInfo propertyInfo,
- object o,
- string itemName)
- {
- BuildItemGroup newItems = CollectItemGroup (propertyInfo, o, itemName);
- if (parentProject.EvaluatedItemsByName.Contains (itemName)) {
- BuildItemGroup big = (BuildItemGroup) parentProject.EvaluatedItemsByName [itemName];
- big.Clear ();
- parentProject.EvaluatedItemsByName.Remove (itemName);
- parentProject.EvaluatedItemsByName.Add (itemName, newItems);
- } else {
- parentProject.EvaluatedItemsByName.Add (itemName, newItems);
- }
- }
-
- private void PublishProperty (PropertyInfo propertyInfo,
+ void PublishProperty (PropertyInfo propertyInfo,
object o,
string propertyName)
{
- BuildProperty bp = CollectProperty (propertyInfo, o, propertyName);
+ if (o == null) {
+ parentProject.EvaluatedProperties.RemoveProperty (propertyName);
+ return;
+ }
+
+ BuildProperty bp;
+ try {
+ bp = ChangeType.ToBuildProperty (o, propertyInfo.PropertyType, propertyName);
+ } catch (Exception e) {
+ throw new Exception (String.Format ("Error publishing Output from task property '{0} {1}' to property named '{2}' : {3}",
+ propertyInfo.PropertyType, propertyInfo.Name, propertyName, e.Message),
+ e);
+ }
parentProject.EvaluatedProperties.AddProperty (bp);
}
-
- private BuildProperty CollectProperty (PropertyInfo propertyInfo, object o, string name)
+
+ // FIXME: cleanup + test
+ void PublishItemGroup (PropertyInfo propertyInfo,
+ object o,
+ string itemName)
{
- string output = null;
- BuildProperty bp;
-
- if (propertyInfo == null)
- throw new ArgumentNullException ("propertyInfo");
if (o == null)
- throw new ArgumentNullException ("o");
- if (name == null)
- throw new ArgumentNullException ("name");
-
- if (propertyInfo.PropertyType == typeof (ITaskItem)) {
- ITaskItem item = (ITaskItem) o;
- bp = ChangeType.TransformToBuildProperty (name, item);
- } else if (propertyInfo.PropertyType == typeof (ITaskItem[])) {
- ITaskItem[] items = (ITaskItem[]) o;
- bp = ChangeType.TransformToBuildProperty (name, items);
- } else {
- if (propertyInfo.PropertyType.IsArray == true) {
- output = ChangeType.TransformToString ((object[])o, propertyInfo.PropertyType);
- } else {
- output = ChangeType.TransformToString (o, propertyInfo.PropertyType);
- }
- bp = ChangeType.TransformToBuildProperty (name, output);
+ return;
+
+ BuildItemGroup newItems;
+ try {
+ newItems = ChangeType.ToBuildItemGroup (o, propertyInfo.PropertyType, itemName);
+ } catch (Exception e) {
+ throw new Exception (String.Format ("Error publishing Output from task property '{0} {1}' to item named '{2}' : {3}",
+ propertyInfo.PropertyType, propertyInfo.Name, itemName, e.Message),
+ e);
}
- return bp;
- }
-
- private BuildItemGroup CollectItemGroup (PropertyInfo propertyInfo, object o, string name)
- {
- BuildItemGroup big;
- string temp;
+
+ newItems.ParentProject = parentProject;
- if (propertyInfo == null)
- throw new ArgumentNullException ("propertyInfo");
- if (o == null)
- throw new ArgumentNullException ("o");
- if (name == null)
- throw new ArgumentNullException ("name");
-
- if (propertyInfo.PropertyType == typeof (ITaskItem)) {
- ITaskItem item = (ITaskItem) o;
- big = ChangeType.TransformToBuildItemGroup (name, item);
- } else if (propertyInfo.PropertyType == typeof (ITaskItem[])) {
- ITaskItem[] items = (ITaskItem[]) o;
- big = ChangeType.TransformToBuildItemGroup (name, items);
+ if (parentProject.EvaluatedItemsByName.ContainsKey (itemName)) {
+ BuildItemGroup big = parentProject.EvaluatedItemsByName [itemName];
+ foreach (BuildItem item in newItems)
+ big.AddItem (item);
} else {
- if (propertyInfo.PropertyType.IsArray == true) {
- temp = ChangeType.TransformToString ((object[]) o, propertyInfo.PropertyType);
- } else {
- temp = ChangeType.TransformToString (o, propertyInfo.PropertyType);
- }
- big = ChangeType.TransformToBuildItemGroup (name, temp);
+ parentProject.EvaluatedItemsByName.Add (itemName, newItems);
}
- return big;
+ foreach (BuildItem bi in newItems)
+ parentProject.EvaluatedItems.AddItem (bi);
}
-
- private object GetObjectFromString (string raw, Type type)
+
+ // returns true, if the @result should be included in the values list
+ bool TryGetObjectFromString (string raw, Type type, out object result)
{
- OldExpression e;
- object result;
-
- e = new OldExpression (parentProject);
- e.ParseSource (raw);
-
- if ((string) e.ConvertTo (typeof (string)) == String.Empty)
- return null;
+ Expression e;
+ result = null;
- result = e.ConvertTo (type);
+ e = new Expression ();
+ e.Parse (raw, ParseOptions.AllowItemsMetadataAndSplit);
+
+ // See rules in comment for 'Prepare'
+ string str = (string) e.ConvertTo (parentProject, typeof (string));
+ if (!type.IsArray && str == String.Empty)
+ return false;
+
+ if (str.Trim ().Length == 0 && type.IsArray &&
+ (type.GetElementType () == typeof (string) || type.GetElementType () == typeof (ITaskItem)))
+ return true;
+
+ result = e.ConvertTo (parentProject, type, ExpressionOptions.ExpandItemRefs);
- return result;
+ return true;
}
}
}