Beispiel #1
0
        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));
        }
Beispiel #2
0
        private void ProcessMetadataElements(ProjectItemElement itemElement, OperationBuilderWithMetadata operationBuilder)
        {
            if (itemElement.HasMetadata)
            {
                operationBuilder.Metadata.AddRange(itemElement.Metadata);

                var values = new List <string>(itemElement.Metadata.Count * 2);

                // 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.
                foreach (var metadatumElement in itemElement.Metadata)
                {
                    // Since we're just attempting to expand properties in order to find referenced items and not expanding metadata,
                    // unexpected errors may occur when evaluating property functions on unexpanded metadata. Just ignore them if that happens.
                    // See: https://github.com/Microsoft/msbuild/issues/3460
                    const ExpanderOptions expanderOptions = ExpanderOptions.ExpandProperties | ExpanderOptions.LeavePropertiesUnexpandedOnError;

                    var valueWithPropertiesExpanded = _expander.ExpandIntoStringLeaveEscaped(
                        metadatumElement.Value,
                        expanderOptions,
                        metadatumElement.Location);

                    var conditionWithPropertiesExpanded = _expander.ExpandIntoStringLeaveEscaped(
                        metadatumElement.Condition,
                        expanderOptions,
                        metadatumElement.ConditionLocation);

                    values.Add(valueWithPropertiesExpanded);
                    values.Add(conditionWithPropertiesExpanded);
                }

                var itemsAndMetadataFound = ExpressionShredder.GetReferencedItemNamesAndMetadata(values);
                if (itemsAndMetadataFound.Items != null)
                {
                    foreach (var itemType in itemsAndMetadataFound.Items)
                    {
                        AddReferencedItemList(itemType, operationBuilder.ReferencedItemLists);
                    }
                }
            }
        }
Beispiel #3
0
            protected bool NeedToExpandMetadataForEachItem(ImmutableList <ProjectMetadataElement> metadata, out ItemsAndMetadataPair itemsAndMetadataFound)
            {
                List <string> values = new List <string>(metadata.Count * 2);

                foreach (var metadataElement in metadata)
                {
                    values.Add(metadataElement.Value);
                    values.Add(metadataElement.Condition);
                }

                itemsAndMetadataFound = ExpressionShredder.GetReferencedItemNamesAndMetadata(values);

                bool needToExpandMetadataForEachItem = false;

                if (itemsAndMetadataFound.Metadata != null && itemsAndMetadataFound.Metadata.Values.Count > 0)
                {
                    // If there is bare metadata of any kind, and the Include involved an item list, we should
                    // run items individually, as even non-built-in metadata might differ between items

                    if (_referencedItemLists.Count >= 0)
                    {
                        needToExpandMetadataForEachItem = true;
                    }
                    else
                    {
                        // If there is bare built-in metadata, we must always run items individually, as that almost
                        // always differs between items.

                        // UNDONE: When batching is implemented for real, we need to make sure that
                        // item definition metadata is included in all metadata operations during evaluation
                        if (itemsAndMetadataFound.Metadata.Values.Count > 0)
                        {
                            needToExpandMetadataForEachItem = true;
                        }
                    }
                }

                return(needToExpandMetadataForEachItem);
            }
Beispiel #4
0
        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));
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
            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());
            }