private RemoveOperation BuildRemoveOperation(string rootDirectory, ProjectItemElement itemElement, bool conditionResult) { RemoveOperationBuilder operationBuilder = new RemoveOperationBuilder(itemElement, conditionResult); ProcessItemSpec(rootDirectory, itemElement.Remove, itemElement.RemoveLocation, operationBuilder); // Process MatchOnMetadata if (itemElement.MatchOnMetadata.Length > 0) { string evaluatedmatchOnMetadata = _expander.ExpandIntoStringLeaveEscaped(itemElement.MatchOnMetadata, ExpanderOptions.ExpandProperties, itemElement.MatchOnMetadataLocation); if (evaluatedmatchOnMetadata.Length > 0) { var matchOnMetadataSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedmatchOnMetadata); foreach (var matchOnMetadataSplit in matchOnMetadataSplits) { AddItemReferences(matchOnMetadataSplit, operationBuilder, itemElement.MatchOnMetadataLocation); string metadataExpanded = _expander.ExpandIntoStringLeaveEscaped(matchOnMetadataSplit, ExpanderOptions.ExpandPropertiesAndItems, itemElement.MatchOnMetadataLocation); var metadataSplits = ExpressionShredder.SplitSemiColonSeparatedList(metadataExpanded); operationBuilder.MatchOnMetadata.AddRange(metadataSplits); } } } operationBuilder.MatchOnMetadataOptions = MatchOnMetadataOptions.CaseSensitive; if (Enum.TryParse(itemElement.MatchOnMetadataOptions, out MatchOnMetadataOptions options)) { operationBuilder.MatchOnMetadataOptions = options; } return(new RemoveOperation(operationBuilder, this)); }
private IncludeOperation BuildIncludeOperation(string rootDirectory, ProjectItemElement itemElement, bool conditionResult) { IncludeOperationBuilder operationBuilder = new IncludeOperationBuilder(itemElement, conditionResult); operationBuilder.ElementOrder = _nextElementOrder++; operationBuilder.RootDirectory = rootDirectory; operationBuilder.ConditionResult = conditionResult; // Process include ProcessItemSpec(rootDirectory, itemElement.Include, itemElement.IncludeLocation, operationBuilder); // Code corresponds to Evaluator.EvaluateItemElement // Process exclude (STEP 4: Evaluate, split, expand and subtract any Exclude) if (itemElement.Exclude.Length > 0) { // Expand properties here, because a property may have a value which is an item reference (ie "@(Bar)"), and // if so we need to add the right item reference string evaluatedExclude = _expander.ExpandIntoStringLeaveEscaped(itemElement.Exclude, ExpanderOptions.ExpandProperties, itemElement.ExcludeLocation); if (evaluatedExclude.Length > 0) { var excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedExclude); foreach (var excludeSplit in excludeSplits) { operationBuilder.Excludes.Add(excludeSplit); AddItemReferences(excludeSplit, operationBuilder, itemElement.ExcludeLocation); } } } // Process Metadata (STEP 5: Evaluate each metadata XML and apply them to each item we have so far) ProcessMetadataElements(itemElement, operationBuilder); return(new IncludeOperation(operationBuilder, this)); }
private List <ItemSpecFragment> BuildItemFragments(IElementLocation itemSpecLocation, string projectDirectory, bool expandProperties) { // Code corresponds to Evaluator.CreateItemsFromInclude var evaluatedItemspecEscaped = ItemSpecString; if (string.IsNullOrEmpty(evaluatedItemspecEscaped)) { return(new List <ItemSpecFragment>()); } // STEP 1: Expand properties in Include if (expandProperties) { evaluatedItemspecEscaped = Expander.ExpandIntoStringLeaveEscaped( ItemSpecString, ExpanderOptions.ExpandProperties, itemSpecLocation); } var semicolonCount = 0; foreach (var c in evaluatedItemspecEscaped) { if (c == ';') { semicolonCount++; } } // estimate the number of fragments with the number of semicolons. This is will overestimate in case of transforms with semicolons, but won't underestimate. var fragments = new List <ItemSpecFragment>(semicolonCount + 1); // STEP 2: Split Include on any semicolons, and take each split in turn if (evaluatedItemspecEscaped.Length > 0) { var splitsEscaped = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedItemspecEscaped); foreach (var splitEscaped in splitsEscaped) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string var itemReferenceFragment = ProcessItemExpression( splitEscaped, itemSpecLocation, projectDirectory, out var isItemListExpression); if (isItemListExpression) { fragments.Add(itemReferenceFragment); } else { // The expression is not of the form "@(X)". Treat as string // Code corresponds to EngineFileUtilities.GetFileList var containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(splitEscaped); var containsRealWildcards = FileMatcher.HasWildcards(splitEscaped); // '*' is an illegal character to have in a filename. // todo: file-system assumption on legal path characters: https://github.com/Microsoft/msbuild/issues/781 if (containsEscapedWildcards && containsRealWildcards) { // Just return the original string. fragments.Add(new ValueFragment(splitEscaped, projectDirectory)); } else if (!containsEscapedWildcards && containsRealWildcards) { // Unescape before handing it to the filesystem. var filespecUnescaped = EscapingUtilities.UnescapeAll(splitEscaped); fragments.Add(new GlobFragment(filespecUnescaped, projectDirectory)); } else { // No real wildcards means we just return the original string. Don't even bother // escaping ... it should already be escaped appropriately since it came directly // from the project file fragments.Add(new ValueFragment(splitEscaped, projectDirectory)); } } } } return(fragments); }
protected override ImmutableList <I> SelectItems(ImmutableList <ItemData> .Builder listBuilder, ImmutableHashSet <string> globsToIgnore) { var itemsToAdd = ImmutableList.CreateBuilder <I>(); Lazy <Func <string, bool> > excludeTester = null; ImmutableList <string> .Builder excludePatterns = ImmutableList.CreateBuilder <string>(); if (_excludes != null) { // STEP 4: Evaluate, split, expand and subtract any Exclude foreach (string exclude in _excludes) { string excludeExpanded = _expander.ExpandIntoStringLeaveEscaped(exclude, ExpanderOptions.ExpandPropertiesAndItems, _itemElement.ExcludeLocation); var excludeSplits = ExpressionShredder.SplitSemiColonSeparatedList(excludeExpanded); excludePatterns.AddRange(excludeSplits); } if (excludePatterns.Count > 0) { excludeTester = new Lazy <Func <string, bool> >(() => EngineFileUtilities.GetFileSpecMatchTester(excludePatterns, _rootDirectory)); } } ISet <string> excludePatternsForGlobs = null; foreach (var fragment in _itemSpec.Fragments) { if (fragment is ItemSpec <P, I> .ItemExpressionFragment itemReferenceFragment) { // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string var itemsFromExpression = _expander.ExpandExpressionCaptureIntoItems( itemReferenceFragment.Capture, _evaluatorData, _itemFactory, ExpanderOptions.ExpandItems, includeNullEntries: false, isTransformExpression: out _, elementLocation: _itemElement.IncludeLocation); itemsToAdd.AddRange( excludeTester != null ? itemsFromExpression.Where(item => !excludeTester.Value(item.EvaluatedInclude)) : itemsFromExpression); } else if (fragment is ValueFragment valueFragment) { string value = valueFragment.TextFragment; if (excludeTester == null || !excludeTester.Value(EscapingUtilities.UnescapeAll(value))) { var item = _itemFactory.CreateItem(value, value, _itemElement.ContainingProject.FullPath); itemsToAdd.Add(item); } } else if (fragment is GlobFragment globFragment) { string glob = globFragment.TextFragment; if (excludePatternsForGlobs == null) { excludePatternsForGlobs = BuildExcludePatternsForGlobs(globsToIgnore, excludePatterns); } string[] includeSplitFilesEscaped; if (MSBuildEventSource.Log.IsEnabled()) { MSBuildEventSource.Log.ExpandGlobStart(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs)); } using (_lazyEvaluator._evaluationProfiler.TrackGlob(_rootDirectory, glob, excludePatternsForGlobs)) { includeSplitFilesEscaped = EngineFileUtilities.GetFileListEscaped( _rootDirectory, glob, excludePatternsForGlobs ); } if (MSBuildEventSource.Log.IsEnabled()) { MSBuildEventSource.Log.ExpandGlobStop(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs)); } foreach (string includeSplitFileEscaped in includeSplitFilesEscaped) { itemsToAdd.Add(_itemFactory.CreateItem(includeSplitFileEscaped, glob, _itemElement.ContainingProject.FullPath)); } } else { throw new InvalidOperationException(fragment.GetType().ToString()); } } return(itemsToAdd.ToImmutable()); }