public void ExpandItemVectorFunctionsMetadataValueMultiItem() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateItemFunctionExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> items = expander.ExpandIntoItemsLeaveEscaped("@(i->Metadata('Meta10')->DirectoryName())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(20, items.Count); Assert.Equal("i", items[5].ItemType); Assert.Equal("i", items[6].ItemType); Assert.Equal(Path.Combine(Directory.GetCurrentDirectory(), @"secondd;rectory"), items[5].EvaluatedInclude); Assert.Equal(Path.Combine(Directory.GetCurrentDirectory(), @"someo;herplace"), items[6].EvaluatedInclude); }
public void ExpandItemVectorFunctionsClearMetadata() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateItemFunctionExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> items = expander.ExpandIntoItemsLeaveEscaped("@(i->ClearMetadata())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(10, items.Count); Assert.Equal("i", items[5].ItemType); Assert.Equal(0, items[5].Metadata.Count()); }
public void ExpandItemVectorFunctionsItemSpecModifier2() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateItemFunctionExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->'%(Meta0)'->'%(Directory)')", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(10, itemsTrue.Count); Assert.Equal("i", itemsTrue[5].ItemType); Assert.Equal(@"firstdirectory\seconddirectory\", itemsTrue[5].EvaluatedInclude); itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->'%(Meta0)'->'%(Filename)')", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(10, itemsTrue.Count); Assert.Equal("i", itemsTrue[5].ItemType); Assert.Equal(@"file0", itemsTrue[5].EvaluatedInclude); itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->'%(Meta0)'->'%(Extension)'->Distinct())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(1, itemsTrue.Count); Assert.Equal("i", itemsTrue[0].ItemType); Assert.Equal(@".ext", itemsTrue[0].EvaluatedInclude); itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->'%(Meta0)'->'%(Filename)'->Substring($(Val)))", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(10, itemsTrue.Count); Assert.Equal("i", itemsTrue[5].ItemType); Assert.Equal(@"le0", itemsTrue[5].EvaluatedInclude); }
public void ExpandItemVectorFunctionsGetDirectoryNameOfMetadataValue() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateItemFunctionExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->Metadata('Meta0')->DirectoryName())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(10, itemsTrue.Count); Assert.Equal("i", itemsTrue[5].ItemType); Assert.Equal(@"c:\firstdirectory\seconddirectory", itemsTrue[5].EvaluatedInclude); }
public void ExpandItemVectorsIntoProjectItemInstancesWithoutSpecifyingItemType() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project); IList<ProjectItemInstance> items = expander.ExpandIntoItemsLeaveEscaped("@(i)", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(2, items.Count); Assert.Equal("i", items[0].ItemType); Assert.Equal("i", items[1].ItemType); Assert.Equal("i0", items[0].EvaluatedInclude); Assert.Equal("i1", items[1].EvaluatedInclude); }
public void ExpandItemVectorFunctionsAnyHaveMetadataValue() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateItemFunctionExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->AnyHaveMetadataValue('Even', 'true'))", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(1, itemsTrue.Count); Assert.Equal("i", itemsTrue[0].ItemType); Assert.Equal("true", itemsTrue[0].EvaluatedInclude); IList<ProjectItemInstance> itemsFalse = expander.ExpandIntoItemsLeaveEscaped("@(i->AnyHaveMetadataValue('Even', 'goop'))", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.Equal(1, itemsFalse.Count); Assert.Equal("i", itemsFalse[0].ItemType); Assert.Equal("false", itemsFalse[0].EvaluatedInclude); }
public void ExpandPropertiesIntoProjectPropertyInstances() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>(); pg.Set(ProjectPropertyInstance.Create("a", "aaa")); pg.Set(ProjectPropertyInstance.Create("b", "bbb")); pg.Set(ProjectPropertyInstance.Create("c", "cc;dd")); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> itemsOut = expander.ExpandIntoItemsLeaveEscaped("foo$(a);$(b);$(c);$(d", itemFactory, ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal(5, itemsOut.Count); }
/// <summary> /// Takes an item specification, evaluates it and expands it into a list of items /// </summary> /// <param name="originalItem">The original item data</param> /// <param name="expander">The expander to use.</param> /// <remarks> /// This code is very close to that which exists in the Evaluator.EvaluateItemXml method. However, because /// it invokes type constructors, and those constructors take arguments of fundamentally different types, it has not /// been refactored. /// </remarks> /// <returns>A list of items.</returns> private IList<ProjectItemInstance> ExpandItemIntoItems ( ProjectItemGroupTaskItemInstance originalItem, Expander<ProjectPropertyInstance, ProjectItemInstance> expander, ISet<string> keepMetadata, ISet<string> removeMetadata ) { ProjectErrorUtilities.VerifyThrowInvalidProject(!(keepMetadata != null && removeMetadata != null), originalItem.KeepMetadataLocation, "KeepAndRemoveMetadataMutuallyExclusive"); IList<ProjectItemInstance> items = new List<ProjectItemInstance>(); // UNDONE: (Refactor) This code also exists in largely the same form in Evaluator.CreateItemsFromInclude. // STEP 1: Expand properties and metadata in Include string evaluatedInclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Include, ExpanderOptions.ExpandPropertiesAndMetadata, originalItem.IncludeLocation); // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedInclude.Length > 0) { IList<string> includeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedInclude); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(this.Project, originalItem.ItemType); foreach (string includeSplit in includeSplits) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool throwaway; IList<ProjectItemInstance> itemsFromSplit = expander.ExpandSingleItemVectorExpressionIntoItems(includeSplit, itemFactory, ExpanderOptions.ExpandItems, false /* do not include null expansion results */, out throwaway, originalItem.IncludeLocation); if (itemsFromSplit != null) { // Expression is in form "@(X)", so add these items directly. foreach (ProjectItemInstance item in itemsFromSplit) { items.Add(item); } } else { // The expression is not of the form "@(X)". Treat as string string[] includeSplitFiles = EngineFileUtilities.GetFileListEscaped(Project.Directory, includeSplit); foreach (string includeSplitFile in includeSplitFiles) { items.Add(new ProjectItemInstance(Project, originalItem.ItemType, includeSplitFile, includeSplit /* before wildcard expansion */, null, null, originalItem.Location.File)); } } } // STEP 4: Evaluate, split, expand and subtract any Exclude if (originalItem.Exclude.Length > 0) { string evaluatedExclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Exclude, ExpanderOptions.ExpandAll, originalItem.ExcludeLocation); if (evaluatedExclude.Length > 0) { IList<string> excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); HashSet<string> excludesUnescapedForComparison = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string excludeSplit in excludeSplits) { string[] excludeSplitFiles = EngineFileUtilities.GetFileListUnescaped(Project.Directory, excludeSplit); foreach (string excludeSplitFile in excludeSplitFiles) { excludesUnescapedForComparison.Add(excludeSplitFile); } } List<ProjectItemInstance> remainingItems = new List<ProjectItemInstance>(); for (int i = 0; i < items.Count; i++) { if (!excludesUnescapedForComparison.Contains(((IItem)items[i]).EvaluatedInclude)) { remainingItems.Add(items[i]); } } items = remainingItems; } } } // Filter the metadata as appropriate if (keepMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => !keepMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } else if (removeMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => removeMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } return items; }
public void ExpandItemVectorFunctionsItemSpecModifier() { ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance(); var expander = CreateItemFunctionExpander(); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i"); IList<ProjectItemInstance> itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->Metadata('Meta0')->Directory())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.AreEqual(10, itemsTrue.Count); Assert.AreEqual("i", itemsTrue[5].ItemType); Assert.AreEqual(@"firstdirectory\seconddirectory\", itemsTrue[5].EvaluatedInclude); itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->Metadata('Meta0')->Filename())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.AreEqual(10, itemsTrue.Count); Assert.AreEqual("i", itemsTrue[5].ItemType); Assert.AreEqual(@"file0", itemsTrue[5].EvaluatedInclude); itemsTrue = expander.ExpandIntoItemsLeaveEscaped("@(i->Metadata('Meta0')->Extension())", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance); Assert.AreEqual(10, itemsTrue.Count); Assert.AreEqual("i", itemsTrue[5].ItemType); Assert.AreEqual(@".ext", itemsTrue[5].EvaluatedInclude); }
/// <summary> /// Takes an item specification, evaluates it and expands it into a list of items /// </summary> /// <param name="originalItem">The original item data</param> /// <param name="expander">The expander to use.</param> /// <param name="keepMetadata">An <see cref="ISet{String}"/> of metadata names to keep.</param> /// <param name="removeMetadata">An <see cref="ISet{String}"/> of metadata names to remove.</param> /// <remarks> /// This code is very close to that which exists in the Evaluator.EvaluateItemXml method. However, because /// it invokes type constructors, and those constructors take arguments of fundamentally different types, it has not /// been refactored. /// </remarks> /// <returns>A list of items.</returns> private IList <ProjectItemInstance> ExpandItemIntoItems ( ProjectItemGroupTaskItemInstance originalItem, Expander <ProjectPropertyInstance, ProjectItemInstance> expander, ISet <string> keepMetadata, ISet <string> removeMetadata ) { //todo this is duplicated logic with the item computation logic from evaluation (in LazyIncludeOperation.SelectItems) ProjectErrorUtilities.VerifyThrowInvalidProject(!(keepMetadata != null && removeMetadata != null), originalItem.KeepMetadataLocation, "KeepAndRemoveMetadataMutuallyExclusive"); IList <ProjectItemInstance> items = new List <ProjectItemInstance>(); // Expand properties and metadata in Include string evaluatedInclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Include, ExpanderOptions.ExpandPropertiesAndMetadata, originalItem.IncludeLocation); if (evaluatedInclude.Length == 0) { return(items); } // Compute exclude fragments, without expanding wildcards var excludes = ImmutableList <string> .Empty.ToBuilder(); if (originalItem.Exclude.Length > 0) { string evaluatedExclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Exclude, ExpanderOptions.ExpandAll, originalItem.ExcludeLocation); if (evaluatedExclude.Length > 0) { var excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); foreach (string excludeSplit in excludeSplits) { excludes.Add(excludeSplit); } } } // Split Include on any semicolons, and take each split in turn var includeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedInclude); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(this.Project, originalItem.ItemType); foreach (string includeSplit in includeSplits) { // If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool throwaway; IList <ProjectItemInstance> itemsFromSplit = expander.ExpandSingleItemVectorExpressionIntoItems(includeSplit, itemFactory, ExpanderOptions.ExpandItems, false /* do not include null expansion results */, out throwaway, originalItem.IncludeLocation); if (itemsFromSplit != null) { // Expression is in form "@(X)", so add these items directly. foreach (ProjectItemInstance item in itemsFromSplit) { items.Add(item); } } else { // The expression is not of the form "@(X)". Treat as string // Pass the non wildcard expanded excludes here to fix https://github.com/Microsoft/msbuild/issues/2621 string[] includeSplitFiles = _engineFileUtilities.GetFileListEscaped( Project.Directory, includeSplit, excludes); foreach (string includeSplitFile in includeSplitFiles) { items.Add(new ProjectItemInstance( Project, originalItem.ItemType, includeSplitFile, includeSplit /* before wildcard expansion */, null, null, originalItem.Location.File)); } } } // Evaluate, split, expand and subtract any Exclude HashSet <string> excludesUnescapedForComparison = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (string excludeSplit in excludes) { string[] excludeSplitFiles = _engineFileUtilities.GetFileListUnescaped(Project.Directory, excludeSplit); foreach (string excludeSplitFile in excludeSplitFiles) { excludesUnescapedForComparison.Add(excludeSplitFile); } } List <ProjectItemInstance> remainingItems = new List <ProjectItemInstance>(); for (int i = 0; i < items.Count; i++) { if (!excludesUnescapedForComparison.Contains(((IItem)items[i]).EvaluatedInclude)) { remainingItems.Add(items[i]); } } items = remainingItems; // Filter the metadata as appropriate if (keepMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => !keepMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } else if (removeMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => removeMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } return(items); }
/// <summary> /// Takes an item specification, evaluates it and expands it into a list of items /// </summary> /// <param name="originalItem">The original item data</param> /// <param name="expander">The expander to use.</param> /// <param name="keepMetadata">An <see cref="ISet{String}"/> of metadata names to keep.</param> /// <param name="removeMetadata">An <see cref="ISet{String}"/> of metadata names to remove.</param> /// <remarks> /// This code is very close to that which exists in the Evaluator.EvaluateItemXml method. However, because /// it invokes type constructors, and those constructors take arguments of fundamentally different types, it has not /// been refactored. /// </remarks> /// <returns>A list of items.</returns> private IList <ProjectItemInstance> ExpandItemIntoItems ( ProjectItemGroupTaskItemInstance originalItem, Expander <ProjectPropertyInstance, ProjectItemInstance> expander, ISet <string> keepMetadata, ISet <string> removeMetadata ) { ProjectErrorUtilities.VerifyThrowInvalidProject(!(keepMetadata != null && removeMetadata != null), originalItem.KeepMetadataLocation, "KeepAndRemoveMetadataMutuallyExclusive"); IList <ProjectItemInstance> items = new List <ProjectItemInstance>(); // UNDONE: (Refactor) This code also exists in largely the same form in Evaluator.CreateItemsFromInclude. // STEP 1: Expand properties and metadata in Include string evaluatedInclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Include, ExpanderOptions.ExpandPropertiesAndMetadata, originalItem.IncludeLocation); // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedInclude.Length > 0) { IList <string> includeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedInclude); ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(this.Project, originalItem.ItemType); foreach (string includeSplit in includeSplits) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string bool throwaway; IList <ProjectItemInstance> itemsFromSplit = expander.ExpandSingleItemVectorExpressionIntoItems(includeSplit, itemFactory, ExpanderOptions.ExpandItems, false /* do not include null expansion results */, out throwaway, originalItem.IncludeLocation); if (itemsFromSplit != null) { // Expression is in form "@(X)", so add these items directly. foreach (ProjectItemInstance item in itemsFromSplit) { items.Add(item); } } else { // The expression is not of the form "@(X)". Treat as string string[] includeSplitFiles = EngineFileUtilities.GetFileListEscaped(Project.Directory, includeSplit); foreach (string includeSplitFile in includeSplitFiles) { items.Add(new ProjectItemInstance(Project, originalItem.ItemType, includeSplitFile, includeSplit /* before wildcard expansion */, null, null, originalItem.Location.File)); } } } // STEP 4: Evaluate, split, expand and subtract any Exclude if (originalItem.Exclude.Length > 0) { string evaluatedExclude = expander.ExpandIntoStringLeaveEscaped(originalItem.Exclude, ExpanderOptions.ExpandAll, originalItem.ExcludeLocation); if (evaluatedExclude.Length > 0) { IList <string> excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); HashSet <string> excludesUnescapedForComparison = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (string excludeSplit in excludeSplits) { string[] excludeSplitFiles = EngineFileUtilities.GetFileListUnescaped(Project.Directory, excludeSplit); foreach (string excludeSplitFile in excludeSplitFiles) { excludesUnescapedForComparison.Add(excludeSplitFile); } } List <ProjectItemInstance> remainingItems = new List <ProjectItemInstance>(); for (int i = 0; i < items.Count; i++) { if (!excludesUnescapedForComparison.Contains(((IItem)items[i]).EvaluatedInclude)) { remainingItems.Add(items[i]); } } items = remainingItems; } } } // Filter the metadata as appropriate if (keepMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => !keepMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } else if (removeMetadata != null) { foreach (var item in items) { var metadataToRemove = item.MetadataNames.Where(name => removeMetadata.Contains(name)); foreach (var metadataName in metadataToRemove) { item.RemoveMetadata(metadataName); } } } return(items); }