Beispiel #1
0
        private static (ITaskItem[] Element, FileMatcher.SearchAction Action, string FileSpec) ExpandWildcards(ITaskItem[] expand)
        {
            // Used to detect and log drive enumerating wildcard patterns.
            string[] files;
            FileMatcher.SearchAction action = FileMatcher.SearchAction.None;
            string itemSpec = string.Empty;

            if (expand == null)
            {
                return(null, action, itemSpec);
            }
            else
            {
                var expanded = new List <ITaskItem>();
                foreach (ITaskItem i in expand)
                {
                    if (FileMatcher.HasWildcards(i.ItemSpec))
                    {
                        (files, action, _) = FileMatcher.Default.GetFiles(null /* use current directory */, i.ItemSpec);
                        itemSpec           = i.ItemSpec;
                        if (action == FileMatcher.SearchAction.FailOnDriveEnumeratingWildcard)
                        {
                            return(expanded.ToArray(), action, itemSpec);
                        }

                        foreach (string file in files)
                        {
                            TaskItem newItem = new TaskItem(i)
                            {
                                ItemSpec = file
                            };

                            // Compute the RecursiveDir portion.
                            FileMatcher.Result match = FileMatcher.Default.FileMatch(i.ItemSpec, file);
                            if (match.isLegalFileSpec && match.isMatch)
                            {
                                if (!string.IsNullOrEmpty(match.wildcardDirectoryPart))
                                {
                                    newItem.SetMetadata(FileUtilities.ItemSpecModifiers.RecursiveDir, match.wildcardDirectoryPart);
                                }
                            }

                            expanded.Add(newItem);
                        }
                    }
                    else
                    {
                        expanded.Add(i);
                    }
                }
                return(expanded.ToArray(), action, itemSpec);
            }
        }
Beispiel #2
0
        private static bool IsValidExclude(string exclude)
        {
            // TODO: assumption on legal path characters: https://github.com/dotnet/msbuild/issues/781
            // Excludes that have both wildcards and non escaped wildcards will never be matched on Windows, because
            // wildcard characters are invalid in Windows paths.
            // Filtering these excludes early keeps the glob expander simpler. Otherwise unescaping logic would reach all the way down to
            // filespec parsing (parse escaped string (to correctly ignore escaped wildcards) and then
            // unescape the path fragments to unfold potentially escaped wildcard chars)
            var hasBothWildcardsAndEscapedWildcards = FileMatcher.HasWildcards(exclude) && EscapingUtilities.ContainsEscapedWildcards(exclude);

            return(!hasBothWildcardsAndEscapedWildcards);
        }
Beispiel #3
0
        void ProcessItemSpec(OperationBuilder operationBuilder, string itemSpec, ElementLocation itemSpecLocation)
        {
            //  Code corresponds to Evaluator.CreateItemsFromInclude

            // STEP 1: Expand properties in Include
            string evaluatedIncludeEscaped = _outerExpander.ExpandIntoStringLeaveEscaped(itemSpec, ExpanderOptions.ExpandProperties, itemSpecLocation);

            // STEP 2: Split Include on any semicolons, and take each split in turn
            if (evaluatedIncludeEscaped.Length > 0)
            {
                IList <string> includeSplitsEscaped = ExpressionShredder.SplitSemiColonSeparatedList(evaluatedIncludeEscaped);

                foreach (string includeSplitEscaped in includeSplitsEscaped)
                {
                    // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string
                    bool isItemListExpression;
                    ProcessSingleItemVectorExpressionForInclude(includeSplitEscaped, operationBuilder, itemSpecLocation, out isItemListExpression);

                    if (!isItemListExpression)
                    {
                        // The expression is not of the form "@(X)". Treat as string

                        //  Code corresponds to EngineFileUtilities.GetFileList
                        bool containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(includeSplitEscaped);
                        bool containsRealWildcards    = FileMatcher.HasWildcards(includeSplitEscaped);

                        if (containsEscapedWildcards && containsRealWildcards)
                        {
                            // Umm, this makes no sense.  The item's Include has both escaped wildcards and
                            // real wildcards.  What does he want us to do?  Go to the file system and find
                            // files that literally have '*' in their filename?  Well, that's not going to
                            // happen because '*' is an illegal character to have in a filename.

                            // Just return the original string.
                            operationBuilder.Operations.Add(Tuple.Create(ItemOperationType.Value, (object)includeSplitEscaped));
                        }
                        else if (!containsEscapedWildcards && containsRealWildcards)
                        {
                            // Unescape before handing it to the filesystem.
                            string filespecUnescaped = EscapingUtilities.UnescapeAll(includeSplitEscaped);
                            operationBuilder.Operations.Add(Tuple.Create(ItemOperationType.Glob, (object)filespecUnescaped));
                        }
                        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
                            operationBuilder.Operations.Add(Tuple.Create(ItemOperationType.Value, (object)includeSplitEscaped));
                        }
                    }
                }
            }
        }
Beispiel #4
0
        internal static bool FilespecHasWildcards(string filespecEscaped)
        {
            if (!FileMatcher.HasWildcards(filespecEscaped))
            {
                return(false);
            }

            // If the item's Include has both escaped wildcards and real wildcards, then it's
            // not clear what they are asking us to do.  Go to the file system and find
            // files that literally have '*' in their filename?  Well, that's not going to
            // happen because '*' is an illegal character to have in a filename.
            return(!EscapingUtilities.ContainsEscapedWildcards(filespecEscaped));
        }
Beispiel #5
0
        /// <summary>
        /// Expand wildcards in the item list.
        /// </summary>
        /// <param name="expand"></param>
        /// <returns>Array of items expanded</returns>
        public static ITaskItem[] ExpandWildcards(ITaskItem[] expand)
        {
            if (expand == null)
            {
                return(null);
            }

            var expanded = new List <ITaskItem>(expand.Length);

            foreach (ITaskItem item in expand)
            {
                if (FileMatcher.HasWildcards(item.ItemSpec))
                {
                    string[] files;
                    string   directoryName = Path.GetDirectoryName(item.ItemSpec);
                    string   searchPattern = Path.GetFileName(item.ItemSpec);

                    // Very often with TLog files we're talking about
                    // a directory and a simply wildcarded filename
                    // Optimize for that case here.
                    if (!FileMatcher.HasWildcards(directoryName) && Directory.Exists(directoryName))
                    {
                        files = Directory.GetFiles(directoryName, searchPattern);
                    }
                    else
                    {
                        files = FileMatcher.Default.GetFiles(null, item.ItemSpec);
                    }

                    foreach (string file in files)
                    {
                        expanded.Add(new TaskItem(item)
                        {
                            ItemSpec = file
                        });
                    }
                }
                else
                {
                    expanded.Add(item);
                }
            }
            return(expanded.ToArray());
        }
Beispiel #6
0
        /// <summary>
        /// Expand wildcards in the item list.
        /// </summary>
        private static ITaskItem[] ExpandWildcards(ITaskItem[] expand)
        {
            if (expand == null)
            {
                return(null);
            }
            else
            {
                var expanded = new List <ITaskItem>();
                foreach (ITaskItem i in expand)
                {
                    if (FileMatcher.HasWildcards(i.ItemSpec))
                    {
                        string[] files = FileMatcher.Default.GetFiles(null /* use current directory */, i.ItemSpec);
                        foreach (string file in files)
                        {
                            TaskItem newItem = new TaskItem(i)
                            {
                                ItemSpec = file
                            };

                            // Compute the RecursiveDir portion.
                            FileMatcher.Result match = FileMatcher.Default.FileMatch(i.ItemSpec, file);
                            if (match.isLegalFileSpec && match.isMatch)
                            {
                                if (!string.IsNullOrEmpty(match.wildcardDirectoryPart))
                                {
                                    newItem.SetMetadata(FileUtilities.ItemSpecModifiers.RecursiveDir, match.wildcardDirectoryPart);
                                }
                            }

                            expanded.Add(newItem);
                        }
                    }
                    else
                    {
                        expanded.Add(i);
                    }
                }
                return(expanded.ToArray());
            }
        }
Beispiel #7
0
        /// <summary>
        /// Expand wildcards in the item list.
        /// </summary>
        /// <param name="expand"></param>
        /// <returns></returns>
        private static ITaskItem[] ExpandWildcards(ITaskItem[] expand)
        {
            if (expand == null)
            {
                return(null);
            }
            else
            {
                ArrayList expanded = new ArrayList();
                foreach (ITaskItem i in expand)
                {
                    if (FileMatcher.HasWildcards(i.ItemSpec))
                    {
                        string[] files = FileMatcher.GetFiles(null /* use current directory */, i.ItemSpec);
                        foreach (string file in files)
                        {
                            TaskItem newItem = new TaskItem((ITaskItem)i);
                            newItem.ItemSpec = file;

                            // Compute the RecursiveDir portion.
                            FileMatcher.Result match = FileMatcher.FileMatch(i.ItemSpec, file);
                            if (match.isLegalFileSpec && match.isMatch)
                            {
                                if (match.wildcardDirectoryPart != null && match.wildcardDirectoryPart.Length > 0)
                                {
                                    newItem.SetMetadata(FileUtilities.ItemSpecModifiers.RecursiveDir, match.wildcardDirectoryPart);
                                }
                            }

                            expanded.Add(newItem);
                        }
                    }
                    else
                    {
                        expanded.Add(i);
                    }
                }
                return((ITaskItem[])expanded.ToArray(typeof(ITaskItem)));
            }
        }
        public static ITaskItem[] ExpandWildcards(ITaskItem[] expand)
        {
            if (expand == null)
            {
                return(null);
            }
            List <ITaskItem> list = new List <ITaskItem>(expand.Length);

            foreach (ITaskItem item in expand)
            {
                if (FileMatcher.HasWildcards(item.ItemSpec))
                {
                    string[] files;
                    string   directoryName = Path.GetDirectoryName(item.ItemSpec);
                    string   fileName      = Path.GetFileName(item.ItemSpec);
                    if (!FileMatcher.HasWildcards(directoryName) && Directory.Exists(directoryName))
                    {
                        files = Directory.GetFiles(directoryName, fileName);
                    }
                    else
                    {
                        files = FileMatcher.GetFiles(null, item.ItemSpec);
                    }
                    foreach (string str3 in files)
                    {
                        TaskItem item2 = new TaskItem(item)
                        {
                            ItemSpec = str3
                        };
                        list.Add(item2);
                    }
                }
                else
                {
                    list.Add(item);
                }
            }
            return(list.ToArray());
        }
Beispiel #9
0
        private static bool FilespecHasWildcards(string filespecEscaped)
        {
            bool containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(filespecEscaped);
            bool containsRealWildcards    = FileMatcher.HasWildcards(filespecEscaped);

            if (containsEscapedWildcards && containsRealWildcards)
            {
                // Umm, this makes no sense.  The item's Include has both escaped wildcards and
                // real wildcards.  What does he want us to do?  Go to the file system and find
                // files that literally have '*' in their filename?  Well, that's not going to
                // happen because '*' is an illegal character to have in a filename.

                return(false);
            }
            else if (!containsEscapedWildcards && containsRealWildcards)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
Beispiel #10
0
        private IEnumerable <ItemFragment> BuildItemFragments(IElementLocation itemSpecLocation, bool expandProperties)
        {
            var builder = ImmutableList.CreateBuilder <ItemFragment>();

            //  Code corresponds to Evaluator.CreateItemsFromInclude
            var evaluatedItemspecEscaped = ItemSpecString;

            if (string.IsNullOrEmpty(evaluatedItemspecEscaped))
            {
                return(builder.ToImmutable());
            }

            // STEP 1: Expand properties in Include
            if (expandProperties)
            {
                evaluatedItemspecEscaped = Expander.ExpandIntoStringLeaveEscaped(ItemSpecString, ExpanderOptions.ExpandProperties, itemSpecLocation);
            }

            // 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
                    bool isItemListExpression;
                    var  itemReferenceFragment = ProcessItemExpression(splitEscaped, itemSpecLocation, out isItemListExpression);

                    if (isItemListExpression)
                    {
                        builder.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.
                            builder.Add(new ValueFragment(splitEscaped, itemSpecLocation.File));
                        }
                        else if (!containsEscapedWildcards && containsRealWildcards)
                        {
                            // Unescape before handing it to the filesystem.
                            var filespecUnescaped = EscapingUtilities.UnescapeAll(splitEscaped);

                            builder.Add(new GlobFragment(filespecUnescaped, itemSpecLocation.File));
                        }
                        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

                            builder.Add(new ValueFragment(splitEscaped, itemSpecLocation.File));
                        }
                    }
                }
            }

            return(builder.ToImmutable());
        }
Beispiel #11
0
        /// <summary>
        /// Used for the purposes of evaluating an item specification. Given a filespec that may include wildcard characters * and
        /// ?, we translate it into an actual list of files. If the input filespec doesn't contain any wildcard characters, and it
        /// doesn't appear to point to an actual file on disk, then we just give back the input string as an array of length one,
        /// assuming that it wasn't really intended to be a filename (as items are not required to necessarily represent files).
        /// </summary>
        /// <owner>RGoel</owner>
        /// <param name="filespec">The filespec to evaluate.</param>
        /// <returns>Array of file paths.</returns>
        internal static string[] GetFileListEscaped
        (
            string directory,
            string filespec
        )
        {
            ErrorUtilities.VerifyThrow(filespec.Length > 0, "Need a valid file-spec.");

            string[] fileList;

            bool containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(filespec);
            bool containsRealWildcards    = FileMatcher.HasWildcards(filespec);

            if (containsEscapedWildcards && containsRealWildcards)
            {
                // Umm, this makes no sense.  The item's Include has both escaped wildcards and
                // real wildcards.  What does he want us to do?  Go to the file system and find
                // files that literally have '*' in their filename?  Well, that's not going to
                // happen because '*' is an illegal character to have in a filename.

                // Just return the original string.
                fileList = new string[] { EscapingUtilities.Escape(filespec) };
            }
            else if (!containsEscapedWildcards && containsRealWildcards)
            {
                // Unescape before handing it to the filesystem.
                string filespecUnescaped = EscapingUtilities.UnescapeAll(filespec);

                // Get the list of actual files which match the filespec.  Put
                // the list into a string array.  If the filespec started out
                // as a relative path, we will get back a bunch of relative paths.
                // If the filespec started out as an absolute path, we will get
                // back a bunch of absolute paths.
                fileList = FileMatcher.GetFiles(directory, filespecUnescaped);

                ErrorUtilities.VerifyThrow(fileList != null, "We must have a list of files here, even if it's empty.");

                // Before actually returning the file list, we sort them alphabetically.  This
                // provides a certain amount of extra determinism and reproducability.  That is,
                // we're sure that the build will behave in exactly the same way every time,
                // and on every machine.
                Array.Sort(fileList);

                // We must now go back and make sure all special characters are escaped because we always
                // store data in the engine in escaped form so it doesn't screw up our parsing.
                // Note that this means that characters that were not escaped in the original filespec
                // may now be escaped, but that's not easy to avoid.
                for (int i = 0; i < fileList.Length; i++)
                {
                    fileList[i] = EscapingUtilities.Escape(fileList[i]);
                }
            }
            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 or the OM host.
                fileList = new string[] { filespec };
            }

            return(fileList);
        }
Beispiel #12
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
                        if (!FileMatcher.HasWildcards(splitEscaped))
                        {
                            // 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));
                        }
                        else if (EscapingUtilities.ContainsEscapedWildcards(splitEscaped))
                        {
                            // '*' is an illegal character to have in a filename.
                            // todo: file-system assumption on legal path characters: https://github.com/dotnet/msbuild/issues/781
                            // Just return the original string.
                            fragments.Add(new ValueFragment(splitEscaped, projectDirectory));
                        }
                        else
                        {
                            // Unescape before handing it to the filesystem.
                            var filespecUnescaped = EscapingUtilities.UnescapeAll(splitEscaped);

                            fragments.Add(new GlobFragment(filespecUnescaped, projectDirectory));
                        }
                    }
                }
            }

            return(fragments);
        }