private void ExecuteAdd(ProjectItemGroupTaskItemInstance child, ItemBucket bucket, ISet <string> keepMetadata, ISet <string> removeMetadata) { // First, collect up the appropriate metadata collections. We need the one from the item definition, if any, and // the one we are using for this batching bucket. ProjectItemDefinitionInstance itemDefinition; Project.ItemDefinitions.TryGetValue(child.ItemType, out itemDefinition); // The NestedMetadataTable will handle the aggregation of the different metadata collections NestedMetadataTable metadataTable = new NestedMetadataTable(child.ItemType, bucket.Expander.Metadata, itemDefinition); IMetadataTable originalMetadataTable = bucket.Expander.Metadata; bucket.Expander.Metadata = metadataTable; // Second, expand the item include and exclude, and filter existing metadata as appropriate. List <ProjectItemInstance> itemsToAdd = ExpandItemIntoItems(child, bucket.Expander, keepMetadata, removeMetadata); // Third, expand the metadata. foreach (ProjectItemGroupTaskMetadataInstance metadataInstance in child.Metadata) { bool condition = ConditionEvaluator.EvaluateCondition ( metadataInstance.Condition, ParserOptions.AllowAll, bucket.Expander, ExpanderOptions.ExpandAll, Project.Directory, metadataInstance.Location, LoggingContext.LoggingService, LoggingContext.BuildEventContext, FileSystems.Default); if (condition) { string evaluatedValue = bucket.Expander.ExpandIntoStringLeaveEscaped(metadataInstance.Value, ExpanderOptions.ExpandAll, metadataInstance.Location); // This both stores the metadata so we can add it to all the items we just created later, and // exposes this metadata to further metadata evaluations in subsequent loop iterations. metadataTable.SetValue(metadataInstance.Name, evaluatedValue); } } // Finally, copy the added metadata onto the new items. The set call is additive. ProjectItemInstance.SetMetadata(metadataTable.AddedMetadata, itemsToAdd); // Add in one operation for potential copy-on-write // Restore the original metadata table. bucket.Expander.Metadata = originalMetadataTable; // Determine if we should NOT add duplicate entries bool keepDuplicates = ConditionEvaluator.EvaluateCondition ( child.KeepDuplicates, ParserOptions.AllowAll, bucket.Expander, ExpanderOptions.ExpandAll, Project.Directory, child.KeepDuplicatesLocation, LoggingContext.LoggingService, LoggingContext.BuildEventContext, FileSystems.Default); if (LogTaskInputs && !LoggingContext.LoggingService.OnlyLogCriticalEvents && itemsToAdd?.Count > 0) { ItemGroupLoggingHelper.LogTaskParameter( LoggingContext, TaskParameterMessageKind.AddItem, child.ItemType, itemsToAdd, logItemMetadata: true, child.Location); } // Now add the items we created to the lookup. bucket.Lookup.AddNewItemsOfItemType(child.ItemType, itemsToAdd, !keepDuplicates); // Add in one operation for potential copy-on-write }
/// <summary> /// Add items to the world. This is the in-target equivalent of an item include expression outside of a target. /// </summary> /// <param name="child">The item specification to evaluate and add.</param> /// <param name="bucket">The batching bucket.</param> private void ExecuteAdd(ProjectItemGroupTaskItemInstance child, ItemBucket bucket, ISet<string> keepMetadata, ISet<string> removeMetadata) { // First, collect up the appropriate metadata collections. We need the one from the item definition, if any, and // the one we are using for this batching bucket. ProjectItemDefinitionInstance itemDefinition = null; Project.ItemDefinitions.TryGetValue(child.ItemType, out itemDefinition); // The NestedMetadataTable will handle the aggregation of the different metadata collections NestedMetadataTable metadataTable = new NestedMetadataTable(child.ItemType, bucket.Expander.Metadata, itemDefinition); IMetadataTable originalMetadataTable = bucket.Expander.Metadata; bucket.Expander.Metadata = metadataTable; // Second, expand the item include and exclude, and filter existing metadata as appropriate. IList<ProjectItemInstance> itemsToAdd = ExpandItemIntoItems(child, bucket.Expander, keepMetadata, removeMetadata); // Third, expand the metadata. foreach (ProjectItemGroupTaskMetadataInstance metadataInstance in child.Metadata) { bool condition = ConditionEvaluator.EvaluateCondition ( metadataInstance.Condition, ParserOptions.AllowAll, bucket.Expander, ExpanderOptions.ExpandAll, Project.Directory, metadataInstance.Location, LoggingContext.LoggingService, LoggingContext.BuildEventContext ); if (condition) { string evaluatedValue = bucket.Expander.ExpandIntoStringLeaveEscaped(metadataInstance.Value, ExpanderOptions.ExpandAll, metadataInstance.Location); // This both stores the metadata so we can add it to all the items we just created later, and // exposes this metadata to further metadata evaluations in subsequent loop iterations. metadataTable.SetValue(metadataInstance.Name, evaluatedValue); } } // Finally, copy the added metadata onto the new items. The set call is additive. ProjectItemInstance.SetMetadata(metadataTable.AddedMetadata, itemsToAdd); // Add in one operation for potential copy-on-write // Restore the original metadata table. bucket.Expander.Metadata = originalMetadataTable; // Determine if we should NOT add duplicate entries bool keepDuplicates = ConditionEvaluator.EvaluateCondition ( child.KeepDuplicates, ParserOptions.AllowAll, bucket.Expander, ExpanderOptions.ExpandAll, Project.Directory, child.KeepDuplicatesLocation, LoggingContext.LoggingService, LoggingContext.BuildEventContext ); if (LogTaskInputs && !LoggingContext.LoggingService.OnlyLogCriticalEvents && itemsToAdd != null && itemsToAdd.Count > 0) { var itemGroupText = ItemGroupLoggingHelper.GetParameterText(ResourceUtilities.GetResourceString("ItemGroupIncludeLogMessagePrefix"), child.ItemType, itemsToAdd.ToArray()); LoggingContext.LogCommentFromText(MessageImportance.Low, itemGroupText); } // Now add the items we created to the lookup. bucket.Lookup.AddNewItemsOfItemType(child.ItemType, itemsToAdd, !keepDuplicates); // Add in one operation for potential copy-on-write }