Beispiel #1
0
        public void TaskOutputsObjectArrayParameter()
        {
            XmlElement taskNode;
            TaskEngine taskEngine;
            MockTask mockTask;
            ItemBucket itemBucket; EngineProxy engineProxy;
            taskNode = CreateXmlTaskNode();

            // Create a task output specification to satisfy GatherGeneratedTaskOutputs.
            XmlElement outputElement = taskNode.OwnerDocument.CreateElement("Output");
            outputElement.SetAttribute("TaskParameter", "ObjectArrayOutputParameter");
            outputElement.SetAttribute("ItemName", "MyItemList");
            taskNode.AppendChild(outputElement);
            TaskOutput myTaskOutputSpecification = new TaskOutput(outputElement);

            InstantiateMockTaskHelper(taskNode, out taskEngine, out mockTask, out itemBucket, out engineProxy);

            taskEngine.GatherGeneratedTaskOutputs(LookupHelpers.CreateLookup(new Hashtable()), myTaskOutputSpecification, "ObjectArrayOutputParameter", "MyItemList", null, mockTask);
        }
Beispiel #2
0
        public void TaskOutputsMyTaskItemArrayParameter()
        {
            XmlElement taskNode;
            TaskEngine taskEngine;
            MockTask mockTask;
            ItemBucket itemBucket; EngineProxy engineProxy;
            taskNode = CreateXmlTaskNode();

            // Create a task output specification to satisfy GatherGeneratedTaskOutputs.
            XmlElement outputElement = taskNode.OwnerDocument.CreateElement("Output");
            outputElement.SetAttribute("TaskParameter", "MyTaskItemArrayOutputParameter");
            outputElement.SetAttribute("ItemName", "MyItemList");
            taskNode.AppendChild(outputElement);
            TaskOutput myTaskOutputSpecification = new TaskOutput(outputElement);

            InstantiateMockTaskHelper(taskNode, out taskEngine, out mockTask, out itemBucket, out engineProxy);

            taskEngine.GatherGeneratedTaskOutputs(GetEnteredScopeLookup(), myTaskOutputSpecification, "MyTaskItemArrayOutputParameter", "MyItemList", null, mockTask);
            // Did not throw InvalidProjectFileException  
        }
Beispiel #3
0
        private void GatherArrayStringAndValueOutputs(Lookup lookup, TaskOutput taskOutputSpecification, string itemName, string propertyName, PropertyInfo parameter, object outputs)
        {
            // if the task has generated outputs (if it didn't, don't do anything)
            if (outputs != null)
            {
                Array convertibleOutputs = (parameter.PropertyType.IsArray)
                    ? (Array)outputs
                    : new object[] { outputs };

                if (taskOutputSpecification.IsItemVector)
                {
                    ErrorUtilities.VerifyThrow((itemName != null) && (itemName.Length > 0), "Need item type.");

                    // to store the outputs as items, use the string representations of the outputs as item-specs
                    foreach (object output in convertibleOutputs)
                    {
                        // if individual outputs in the array are null, ignore them
                        if (output != null)
                        {
                            string stringValueFromTask = (string)Convert.ChangeType(output, typeof(string), CultureInfo.InvariantCulture);

                            // attempting to put an empty string into an item is a no-op (bug #444501).
                            if (stringValueFromTask.Length > 0)
                            {
                                lookup.AddNewItem(new BuildItem(itemName, EscapingUtilities.Escape(stringValueFromTask)));
                            }
                        }
                    }
                }
                else
                {
                    Debug.Assert(taskOutputSpecification.IsProperty);
                    ErrorUtilities.VerifyThrow((propertyName != null) && (propertyName.Length > 0), "Need property name.");

                    // to store an object array in a property, join all the string representations of the objects with
                    // semi-colons to make the property value
                    StringBuilder joinedOutputs = new StringBuilder();

                    foreach (object output in convertibleOutputs)
                    {
                        // if individual outputs in the array are null, ignore them
                        if (output != null)
                        {
                            if (joinedOutputs.Length > 0)
                            {
                                joinedOutputs.Append(';');
                            }

                            string stringValueFromTask = (string)Convert.ChangeType(output, typeof(string), CultureInfo.InvariantCulture);
                            joinedOutputs.Append(EscapingUtilities.Escape(stringValueFromTask));
                        }
                    }

                    lookup.SetProperty(new BuildProperty(propertyName, joinedOutputs.ToString(), PropertyType.OutputProperty));
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Uses the given task output specification to grab the task's outputs using .NET reflection.
        /// </summary>
        /// <remarks>
        /// This method is "internal" for unit-testing purposes only.
        /// </remarks>
        /// <param name="taskOutputSpecification"></param>
        /// <param name="taskParameterName"></param>
        /// <param name="itemName">can be null</param>
        /// <param name="propertyName">can be null</param>
        /// <param name="task"></param>
        /// <returns>true, if successful</returns>
        internal bool GatherGeneratedTaskOutputs
        (
            Lookup lookup,
            TaskOutput taskOutputSpecification,
            string taskParameterName,
            string itemName,
            string propertyName,
            ITask task)
        {
            ErrorUtilities.VerifyThrow(task != null, "Need instantiated task to retrieve outputs from.");

            bool gatheredGeneratedOutputsSuccessfully = true;

            try
            {
                PropertyInfo parameter = TaskClass.GetProperty(taskParameterName);

                // flag an error if we find a parameter that has no .NET property equivalent
                ProjectErrorUtilities.VerifyThrowInvalidProject(parameter != null,
                    taskOutputSpecification.TaskParameterAttribute,
                    "UnexpectedTaskOutputAttribute", taskParameterName, TaskName);

                // output parameters must have their corresponding .NET properties marked with the Output attribute
                ProjectErrorUtilities.VerifyThrowInvalidProject(TaskClass.GetNamesOfPropertiesWithOutputAttribute().ContainsKey(taskParameterName),
                    taskOutputSpecification.TaskParameterAttribute,
                    "UnmarkedOutputTaskParameter", parameter.Name, TaskName);

                // grab the outputs from the task's designated output parameter (which is a .NET property)
                object outputs = parameter.GetValue(task, null);
                Type type = parameter.PropertyType;

                // don't use the C# "is" operator as it always returns false if the object is null
                if (
                    typeof(ITaskItem[]).IsAssignableFrom(type) ||   /* ITaskItem array or derived type, or */
                    typeof(ITaskItem).IsAssignableFrom(type)        /* ITaskItem or derived type */
                   )
                {
                    GatherTaskItemOutputs(lookup, taskOutputSpecification, itemName, propertyName, outputs);
                }
                // don't use the C# "is" operator as it always returns false if the object is null
                else if (
                    (type.IsArray && type.GetElementType().IsValueType) ||  /* array of value types, or */
                    (type == typeof(string[])) ||                           /* string array, or */
                    (type.IsValueType) ||                                   /* value type, or */
                    (type == typeof(string))                                /* string */
                    )
                {
                    GatherArrayStringAndValueOutputs(lookup, taskOutputSpecification, itemName, propertyName, parameter, outputs);
                }
                else
                {
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, taskOutputSpecification.TaskParameterAttribute,
                        "UnsupportedTaskParameterTypeError", parameter.PropertyType, parameter.Name, TaskName);
                }
            }
            // handle invalid TaskItems in task outputs
            catch (InvalidOperationException e)
            {
                loggingServices.LogError(buildEventContext, Utilities.CreateBuildEventFileInfo(taskOutputSpecification.TaskParameterAttribute, projectFileOfTaskNode),
                    "InvalidTaskItemsInTaskOutputs", TaskName, taskParameterName, e.Message);

                gatheredGeneratedOutputsSuccessfully = false;
            }
            // handle any exception thrown by the task's getter
            catch (TargetInvocationException e)
            {
                // Exception thrown by the called code itself
                // Log the stack, so the task vendor can fix their code
                // Log the task line number, whatever the value of ContinueOnError;
                // because this will be a hard error anyway.
                loggingServices.LogFatalTaskError(buildEventContext, e.InnerException,
                    CreateBuildEventFileInfoForTask(),
                    TaskName);

                // We do not recover from a task exception while getting outputs,
                // so do not merely set gatheredGeneratedOutputsSuccessfully = false; here

                ProjectErrorUtilities.VerifyThrowInvalidProject(false, taskOutputSpecification.TaskParameterAttribute,
                    "FailedToRetrieveTaskOutputs", TaskName, taskParameterName, e.InnerException.Message);
            }
            catch (Exception e) // Catching Exception, but rethrowing unless it's a well-known exception.
            {
                if (ExceptionHandling.NotExpectedReflectionException(e))
                    throw;

                ProjectErrorUtilities.VerifyThrowInvalidProject(false, taskOutputSpecification.TaskParameterAttribute,
                    "FailedToRetrieveTaskOutputs", TaskName, taskParameterName, e.Message);
            }

            return gatheredGeneratedOutputsSuccessfully;
        }
Beispiel #5
0
        /// <summary>
        /// Parses the task element for its output specifications, which are declared using &lt;Output&gt; tags.
        /// </summary>
        private List<TaskOutput> GetTaskOutputSpecifications(bool showWarnings)
        {
            List<TaskOutput> taskOutputSpecifications = new List<TaskOutput>();

            foreach (XmlNode childNode in taskNode.ChildNodes)
            {
                ProjectErrorUtilities.VerifyThrowInvalidProject(XMakeElements.IsValidTaskChildNode(childNode), childNode,
                    "UnrecognizedChildElement", childNode.Name, TaskName);

                if (childNode.Name == XMakeElements.output)
                {
                    TaskOutput taskOutputSpecification = new TaskOutput((XmlElement)childNode);

                    // The "ItemName" attribute of the <Output> tag is usually just a straight 
                    // string representing the item name.  If it contains any "@" signs, the 
                    // project author most likely made a mistake, and so we throw a warning here.
                    XmlAttribute itemNameAttribute = taskOutputSpecification.ItemNameAttribute;
                    if (showWarnings && taskOutputSpecification.IsItemVector &&
                        (-1 != itemNameAttribute.Value.IndexOf('@')))
                    {
                        loggingServices.LogWarning(buildEventContext, Utilities.CreateBuildEventFileInfo(itemNameAttribute,
                            projectFileOfTaskNode), "AtSignInTaskOutputItemName", itemNameAttribute.Value);
                    }

                    // The "PropertyName" attribute of the <Output> tag is usually just a straight 
                    // string representing the property name.  If it contains any "$" signs, the 
                    // project author most likely made a mistake, and so we throw a warning here.
                    XmlAttribute propertyNameAttribute = taskOutputSpecification.PropertyNameAttribute;
                    if (showWarnings && taskOutputSpecification.IsProperty &&
                        (-1 != propertyNameAttribute.Value.IndexOf('$')))
                    {
                        loggingServices.LogWarning(buildEventContext, Utilities.CreateBuildEventFileInfo(propertyNameAttribute,
                            projectFileOfTaskNode), "DollarSignInTaskOutputPropertyName", propertyNameAttribute.Value);
                    }

                    taskOutputSpecifications.Add(taskOutputSpecification);
                }
            }

            return taskOutputSpecifications;
        }
Beispiel #6
0
        /// <summary>
        /// Uses the given task output specification to (statically) infer the task's outputs.
        /// </summary>
        /// <param name="taskOutputSpecification"></param>
        /// <param name="taskParameterName"></param>
        /// <param name="itemName">can be null</param>
        /// <param name="propertyName">can be null</param>
        /// <param name="bucket"></param>
        private void InferTaskOutputs
        (
            Lookup lookup,
            TaskOutput taskOutputSpecification,
            string taskParameterName,
            string itemName,
            string propertyName,
            ItemBucket bucket
        )
        {
            // if the task has a value set for the output parameter, expand all embedded properties and item metadata in it
            XmlAttribute taskParameterAttribute = null;

            // Lookup attribute name needs to be case-insensitive
            // DevDiv bugs: 33981
            foreach (XmlAttribute taskNodeAttribute in taskNode.Attributes)
            {
                if (String.Compare(taskNodeAttribute.Name, taskParameterName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    taskParameterAttribute = taskNodeAttribute;
                    break;
                }
            }
 
            if (taskParameterAttribute != null)
            {
                if (taskOutputSpecification.IsItemVector)
                {
                    // This is an output item.

                    ErrorUtilities.VerifyThrow((itemName != null) && (itemName.Length > 0), "Need item type.");

                    // Expand only with properties first, so that expressions like Include="@(foo)" will transfer the metadata of the "foo" items as well, not just their item specs.
                    Expander propertyAndMetadataExpander = new Expander(bucket.Expander, ExpanderOptions.ExpandPropertiesAndMetadata);
                    List<string> outputItemSpecs = propertyAndMetadataExpander.ExpandAllIntoStringListLeaveEscaped(taskParameterAttribute);

                    foreach (string outputItemSpec in outputItemSpecs)
                    {
                        BuildItemGroup items = bucket.Expander.ExpandSingleItemListExpressionIntoItemsLeaveEscaped(outputItemSpec, taskParameterAttribute);

                        // if the output item-spec is an item vector, get the items in it
                        if (items != null)
                        {
                            foreach (BuildItem item in items)
                            {
                                // we want to preserve the attributes on the item
                                BuildItem clonedItem = item.VirtualClone();
                                // but we do need to change the item type
                                clonedItem.Name = itemName;

                                lookup.AddNewItem(clonedItem);
                            }
                        }
                        else
                        {
                            // if the output item-spec is not an item vector, accept it as-is
                            lookup.AddNewItem(new BuildItem(itemName, outputItemSpec));
                        }
                    }
                }
                else
                {
                    // This is an output property.

                    Debug.Assert(taskOutputSpecification.IsProperty);
                    ErrorUtilities.VerifyThrow((propertyName != null) && (propertyName.Length > 0), "Need property name.");

                    string taskParameterValue = bucket.Expander.ExpandAllIntoString(taskParameterAttribute);

                    if (taskParameterValue.Length > 0)
                    {
                        lookup.SetProperty(new BuildProperty(propertyName, taskParameterValue, PropertyType.OutputProperty));
                    }
                }
            }
        }
Beispiel #7
0
        private void GatherTaskItemOutputs(Lookup lookup, TaskOutput taskOutputSpecification, string itemName, string propertyName, object outputs)
        {
            // if the task has generated outputs (if it didn't, don't do anything)
            if (outputs != null)
            {
                ITaskItem[] taskItemOutputs = (outputs is ITaskItem[])
                    ? (ITaskItem[])outputs
                    : new ITaskItem[] { (ITaskItem)outputs };

                if (taskOutputSpecification.IsItemVector)
                {
                    ErrorUtilities.VerifyThrow((itemName != null) && (itemName.Length > 0), "Need item type.");

                    foreach (ITaskItem output in taskItemOutputs)
                    {
                        // if individual items in the array are null, ignore them
                        if (output != null)
                        {
                            lookup.AddNewItem(new BuildItem(itemName, output));
                        }
                    }
                }
                else
                {
                    Debug.Assert(taskOutputSpecification.IsProperty);
                    ErrorUtilities.VerifyThrow((propertyName != null) && (propertyName.Length > 0), "Need property name.");

                    // to store an ITaskItem array in a property, join all the item-specs with semi-colons to make the
                    // property value, and ignore/discard the attributes on the ITaskItems
                    StringBuilder joinedOutputs = new StringBuilder();

                    foreach (ITaskItem output in taskItemOutputs)
                    {
                        // if individual items in the array are null, ignore them
                        if (output != null)
                        {
                            if (joinedOutputs.Length > 0)
                            {
                                joinedOutputs.Append(';');
                            }

                            joinedOutputs.Append(EscapingUtilities.Escape(output.ItemSpec));
                        }
                    }

                    lookup.SetProperty(new BuildProperty(propertyName, joinedOutputs.ToString(), PropertyType.OutputProperty));
                }
            }
        }