Beispiel #1
0
        /// <summary>
        /// Clones the BuildItemGroup.  A shallow clone here is one that references
        /// the same BuildItem objects as the original, whereas a deep clone actually
        /// clones the BuildItem objects as well.  If this is a persisted BuildItemGroup,
        /// only deep clones are allowed, because you can't have the same XML
        /// element belonging to two parents.
        /// </summary>
        public BuildItemGroup Clone(bool deepClone)
        {
            BuildItemGroup clone;

            if (IsPersisted)
            {
                // Only deep clones are permitted when dealing with a persisted <ItemGroup>.
                // This is because a shallow clone would attempt to add the same item
                // elements to two different parent <ItemGroup> elements, and this is
                // not allowed.
                ErrorUtilities.VerifyThrowInvalidOperation(deepClone, "ShallowCloneNotAllowed");

                // Do not set the ParentProject on the cloned BuildItemGroup, because it isn't really
                // part of the project.
                clone           = new BuildItemGroup(xml.OwnerDocument, importedFromAnotherProject, null);
                clone.Condition = Condition;
            }
            else
            {
                clone = new BuildItemGroup();
            }

            // Loop through every BuildItem in our collection, and add those same Items
            // to the cloned collection.

            clone.EnsureCapacity(this.Count); // PERF: important to pre-size

            foreach (BuildItem item in this)
            {
                // If the caller requested a deep clone, then clone the BuildItem object,
                // and add the new BuildItem to the new BuildItemGroup.  Otherwise, just add
                // a reference to the existing BuildItem object to the new BuildItemGroup.
                clone.AddItem(deepClone ? item.Clone() : item);
            }

            return(clone);
        }
Beispiel #2
0
        /// <summary>
        /// Extracts the items in the given item vector.
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="itemVector"></param>
        /// <returns>The contents of the item vector (with transforms applied).</returns>
        private BuildItemGroup ItemizeItemVector(Match itemVector)
        {
            ErrorUtilities.VerifyThrow(itemVector.Success, "Need a valid item vector.");

            string itemType  = itemVector.Groups["TYPE"].Value;
            string transform = (itemVector.Groups["TRANSFORM_SPECIFICATION"].Length > 0)
                ? itemVector.Groups["TRANSFORM"].Value
                : null;

            BuildItemGroup items = null;

            if (readOnlyLookup != null)
            {
                items = readOnlyLookup.GetItems(itemType);
            }

            if (items == null)
            {
                items = new BuildItemGroup();
            }
            else
            {
                items = items.Clone((transform != null) /* deep clone on transforms because we're actually creating new items */);
            }

            if (transform != null)
            {
                foreach (BuildItem item in items)
                {
                    itemUnderTransformation = item;
                    item.SetFinalItemSpecEscaped(itemMetadataPattern.Replace(transform, new MatchEvaluator(ExpandItemMetadata)));
                }
            }

            return(items);
        }
Beispiel #3
0
Datei: When.cs Projekt: 3F/IeXod
        /// <summary>
        /// Helper method for processing the children of a When. Only parses Choose,
        /// PropertyGroup, and ItemGroup. All other tags result in an error.
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <owner>DavidLe</owner>
        /// <param name="parentNode"></param>
        /// <param name="parentProjectForChildren"></param>
        /// <param name="importedFromAnotherProject"></param>
        /// <param name="options"></param>
        /// <param name="nestingDepth">Number of parent &lt;Choose&gt; elements this is nested inside</param>
        private void ProcessWhenChildren
        (
            XmlElement parentNode,
            Project parentProjectForChildren, bool importedFromAnotherProject,
            int nestingDepth
        )
        {
            // Loop through the child nodes of the <When> element.
            foreach (XmlNode whenChildNode in parentNode)
            {
                switch (whenChildNode.NodeType)
                {
                // Handle XML comments under the <When> node (just ignore them).
                case XmlNodeType.Comment:
                // fall through
                case XmlNodeType.Whitespace:
                    // ignore whitespace
                    break;

                case XmlNodeType.Element:
                {
                    // Make sure this element doesn't have a custom namespace
                    ProjectXmlUtilities.VerifyThrowProjectValidNamespace((XmlElement)whenChildNode);

                    // The only three types of child nodes that a <When> element can contain
                    // are <PropertyGroup>, <ItemGroup> and <Choose>.
                    switch (whenChildNode.Name)
                    {
                    case XMakeElements.itemGroup:
                        BuildItemGroup newItemGroup = new BuildItemGroup((XmlElement)whenChildNode, importedFromAnotherProject, parentProjectForChildren);
                        this.propertyAndItemLists.InsertAtEnd(newItemGroup);
                        break;

                    // Process the <PropertyGroup> element.
                    case XMakeElements.propertyGroup:
                        BuildPropertyGroup newPropertyGroup = new BuildPropertyGroup(parentProjectForChildren, (XmlElement)whenChildNode, importedFromAnotherProject);
                        newPropertyGroup.EnsureNoReservedProperties();
                        this.propertyAndItemLists.InsertAtEnd(newPropertyGroup);
                        break;

                    // Process the <Choose> element.
                    case XMakeElements.choose:
                        Choose newChoose = new Choose(parentProjectForChildren, this.PropertyAndItemLists, (XmlElement)whenChildNode,
                                                      importedFromAnotherProject, nestingDepth);
                        this.propertyAndItemLists.InsertAtEnd(newChoose);
                        break;

                    default:
                    {
                        ProjectXmlUtilities.ThrowProjectInvalidChildElement(whenChildNode);
                        break;
                    }
                    }
                }
                break;

                default:
                {
                    ProjectXmlUtilities.ThrowProjectInvalidChildElement(whenChildNode);
                    break;
                }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Gets the items of the specified type that are visible in the current scope.
        /// If no match is found, returns null.
        /// Caller must not modify the group returned.
        /// </summary>
        internal BuildItemGroup GetItems(string name)
        {
            // The visible items consist of the adds (accumulated as we go down)
            // plus the first set of regular items we encounter
            // minus any removes
            BuildItemGroup allAdds    = null;
            BuildItemGroup allRemoves = null;
            Dictionary <BuildItem, Dictionary <string, string> > allModifies = null;
            BuildItemGroup groupFound = null;

            foreach (LookupEntry entry in lookupEntries)
            {
                // Accumulate adds while we look downwards
                if (entry.Adds != null)
                {
                    BuildItemGroup adds = (BuildItemGroup)entry.Adds[name];
                    if (adds != null)
                    {
                        allAdds = CreateItemGroupIfNecessary(allAdds);
                        allAdds.ImportItems(adds);
                    }
                }

                // Accumulate removes while we look downwards
                if (entry.Removes != null)
                {
                    BuildItemGroup removes = (BuildItemGroup)entry.Removes[name];
                    if (removes != null)
                    {
                        allRemoves = CreateItemGroupIfNecessary(allRemoves);
                        allRemoves.ImportItems(removes);
                    }
                }

                // Accumulate modifications as we look downwards
                if (entry.Modifies != null)
                {
                    Dictionary <BuildItem, Dictionary <string, string> > modifies;
                    if (entry.Modifies.TryGetValue(name, out modifies))
                    {
                        if (allModifies == null)
                        {
                            allModifies = new Dictionary <BuildItem, Dictionary <string, string> >();
                        }

                        // We already have some modifies for this type
                        foreach (KeyValuePair <BuildItem, Dictionary <string, string> > modify in modifies)
                        {
                            // If earlier scopes modify the same metadata on the same item,
                            // they have priority
                            MergeModificationsIntoModificationTable(allModifies, modify, ModifyMergeType.FirstWins);
                        }
                    }
                }

                if (entry.Items != null)
                {
                    groupFound = (BuildItemGroup)entry.Items[name];
                    if (groupFound != null)
                    {
                        // Found a group: we go no further
                        break;
                    }
                }

                if (entry.TruncateLookupsAtThisScope)
                {
                    break;
                }
            }

            if ((allAdds == null || allAdds.Count == 0) &&
                (allRemoves == null || allRemoves.Count == 0) &&
                (allModifies == null || allModifies.Count == 0))
            {
                // We can just hand out this group verbatim -
                // that avoids any importing
                if (groupFound == null)
                {
                    groupFound = new BuildItemGroup();
                }

                return(groupFound);
            }

            // We have adds and/or removes and/or modifies to incorporate.
            // We can't modify the group, because that might
            // be visible to other batches; we have to create
            // a new one.
            BuildItemGroup result = new BuildItemGroup();

            if (groupFound != null)
            {
                result.ImportItems(groupFound);
            }
            // Removes are processed after adds; this means when we remove there's no need to concern ourselves
            // with the case where the item being removed is in an add table somewhere. The converse case is not possible
            // using a project file: a project file cannot create an item that was already removed, it can only create
            // a unique new item.
            if (allAdds != null)
            {
                result.ImportItems(allAdds);
            }

            if (allRemoves != null)
            {
                result.RemoveItems(allRemoves);
            }

            // Modifies can be processed last; if a modified item was removed, the modify will be ignored
            if (allModifies != null)
            {
                ApplyModifies(result, allModifies);
            }

            return(result);
        }
Beispiel #5
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="itemGroup">Item group this class should proxy</param>
 public BuildItemGroupProxy(BuildItemGroup itemGroup)
 {
     this.backingItemGroup = itemGroup;
 }
Beispiel #6
0
        /// <summary>
        /// Evaluates an item group that's *outside* of a Target.
        /// Metadata is not allowed on conditions, and we against the parent project.
        /// </summary>
        internal void Evaluate
        (
            BuildPropertyGroup existingProperties,
            Hashtable existingItemsByName,
            bool collectItemsIgnoringCondition,
            bool collectItemsRespectingCondition,
            ProcessingPass pass
        )
        {
            ErrorUtilities.VerifyThrow(pass == ProcessingPass.Pass2, "Pass should be Pass2 for ItemGroups.");
            ErrorUtilities.VerifyThrow(collectItemsIgnoringCondition || collectItemsRespectingCondition, "collectItemsIgnoringCondition and collectItemsRespectingCondition can't both be false.");

            Expander expander = new Expander(existingProperties, existingItemsByName, ExpanderOptions.ExpandAll);

            bool itemGroupCondition = Utilities.EvaluateCondition(Condition,
                                                                  (IsPersisted ? xml.ConditionAttribute : null),
                                                                  expander,
                                                                  ParserOptions.AllowPropertiesAndItemLists,
                                                                  parentProject);

            if (!itemGroupCondition && !collectItemsIgnoringCondition)
            {
                // Neither list needs updating
                return;
            }

            foreach (BuildItem currentItem in this)
            {
                bool itemCondition = Utilities.EvaluateCondition(currentItem.Condition,
                                                                 currentItem.ConditionAttribute,
                                                                 expander,
                                                                 ParserOptions.AllowPropertiesAndItemLists,
                                                                 parentProject);

                if (!itemCondition && !collectItemsIgnoringCondition)
                {
                    // Neither list needs updating
                    continue;
                }

                if (collectItemsIgnoringCondition)
                {
                    // Since we're re-evaluating the project, clear out the previous list of child items
                    // for each persisted item tag.
                    currentItem.ChildItems.Clear();
                }

                currentItem.EvaluateAllItemMetadata(expander, ParserOptions.AllowPropertiesAndItemLists, parentProject.ParentEngine.LoggingServices, parentProject.ProjectBuildEventContext);
                BuildItemGroup items = BuildItemGroup.ExpandItemIntoItems(parentProject.ProjectDirectory, currentItem, expander, false /* do not expand metadata */);

                foreach (BuildItem item in items)
                {
                    BuildItem newItem = BuildItem.CreateClonedParentedItem(item, currentItem);

                    if (itemGroupCondition && itemCondition && collectItemsRespectingCondition)
                    {
                        parentProject.AddToItemListByName(newItem);
                    }

                    if (collectItemsIgnoringCondition)
                    {
                        parentProject.AddToItemListByNameIgnoringCondition(newItem);

                        // Set up the other half of the parent/child relationship.
                        newItem.ParentPersistedItem.ChildItems.AddItem(newItem);
                    }
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// Of all the item lists that are referenced in this batchable object, which ones should we
        /// batch on, and which ones should we just pass in wholesale to every invocation of the
        /// target/task?
        ///
        /// Rule #1.  If the user has referenced any *qualified* item metadata such as %(EmbeddedResource.Culture),
        /// then that item list "EmbeddedResource" will definitely get batched.
        ///
        /// Rule #2.  For all the unqualified item metadata such as %(Culture), we make sure that
        /// every single item in every single item list being passed into the task contains a value
        /// for that metadata.  If not, it's an error.  If so, we batch all of those item lists.
        ///
        /// All other item lists will not be batched, and instead will be passed in wholesale to all buckets.
        /// </summary>
        /// <returns>Hashtable containing the item names that should be batched.</returns>
        private static Hashtable GetItemListsToBeBatched
        (
            XmlNode parentNode,
            Dictionary <string, MetadataReference> consumedMetadataReferences, // Key is [string] potentially qualified metadata name
            // Value is [struct MetadataReference]
            Hashtable consumedItemReferenceNames,                              // Key is [string] item name.
            // Value is always String.Empty (unused).
            Lookup lookup
        )
        {
            // The keys in this hashtable are the names of the items that we will batch on.
            // The values are always String.Empty (not used).
            Hashtable itemListsToBeBatched = new Hashtable(StringComparer.OrdinalIgnoreCase);

            // Loop through all the metadata references and find the ones that are qualified
            // with an item name.
            foreach (MetadataReference consumedMetadataReference in consumedMetadataReferences.Values)
            {
                if (consumedMetadataReference.itemName != null)
                {
                    // Rule #1.  Qualified metadata reference.
                    // For metadata references that are qualified with an item name
                    // (e.g., %(EmbeddedResource.Culture) ), we add that item name to the list of
                    // consumed item names, even if the item name wasn't otherwise referenced via
                    // @(...) syntax, and even if every item in the list doesn't necessary contain
                    // a value for this metadata.  This is the special power that you get by qualifying
                    // the metadata reference with an item name.
                    itemListsToBeBatched[consumedMetadataReference.itemName] = String.Empty;

                    // Also add this qualified item to the consumed item references list, because
                    // %(EmbeddedResource.Culture) effectively means that @(EmbeddedResource) is
                    // being consumed, even though we may not see literally "@(EmbeddedResource)"
                    // in the tag anywhere.  Adding it to this list allows us (down below in this
                    // method) to check that every item in this list has a value for each
                    // unqualified metadata reference.
                    consumedItemReferenceNames = Utilities.CreateTableIfNecessary(consumedItemReferenceNames);
                    consumedItemReferenceNames[consumedMetadataReference.itemName] = String.Empty;
                }
            }

            // Loop through all the metadata references and find the ones that are unqualified.
            foreach (MetadataReference consumedMetadataReference in consumedMetadataReferences.Values)
            {
                if (consumedMetadataReference.itemName == null)
                {
                    // Rule #2.  Unqualified metadata reference.
                    // For metadata references that are unqualified, every single consumed item
                    // must contain a value for that metadata.  If any item doesn't, it's an error
                    // to use unqualified metadata.
                    if (consumedItemReferenceNames != null)
                    {
                        foreach (string consumedItemName in consumedItemReferenceNames.Keys)
                        {
                            // Loop through all the items in the item list.
                            BuildItemGroup items = lookup.GetItems(consumedItemName);

                            if (items != null)
                            {
                                // Loop through all the items in the BuildItemGroup.
                                foreach (BuildItem item in items)
                                {
                                    ProjectErrorUtilities.VerifyThrowInvalidProject(
                                        item.HasMetadata(consumedMetadataReference.metadataName),
                                        parentNode, "ItemDoesNotContainValueForUnqualifiedMetadata",
                                        item.Include, consumedItemName, consumedMetadataReference.metadataName);
                                }
                            }

                            // This item list passes the test of having every single item containing
                            // a value for this metadata.  Therefore, add this item list to the batching list.
                            // Also, to save doing lookup.GetItems again, put the items in the table as the value.
                            itemListsToBeBatched[consumedItemName] = items;
                        }
                    }
                }
            }

            return(itemListsToBeBatched);
        }