Beispiel #1
0
        private static RecursiveStepResult GetFilesRecursiveStep
        (
            RecursionState recursionState,
            string projectDirectory,
            bool stripProjectDirectory,
            GetFileSystemEntries getFileSystemEntries
        )
        {
            RecursiveStepResult ret = new RecursiveStepResult();

            /*
             * Get the matching files.
             */
            bool considerFiles = false;

            // Only consider files if...
            if (recursionState.RemainingWildcardDirectory.Length == 0)
            {
                // We've reached the end of the wildcard directory elements.
                considerFiles = true;
            }
            else if (recursionState.RemainingWildcardDirectory.IndexOf(recursiveDirectoryMatch, StringComparison.Ordinal) == 0)
            {
                // or, we've reached a "**" so everything else is matched recursively.
                considerFiles = true;
            }

            if (considerFiles)
            {
                string[] files = getFileSystemEntries(FileSystemEntity.Files, recursionState.BaseDirectory,
                    recursionState.SearchData.Filespec, projectDirectory, stripProjectDirectory);

                bool needToProcessEachFile = recursionState.SearchData.Filespec == null || recursionState.SearchData.ExtensionLengthToEnforce != 0;
                if (needToProcessEachFile)
                {
                    List<string> listOfFiles = new List<string>();
                    foreach (string file in files)
                    {
                        if ((recursionState.SearchData.Filespec != null) ||
                            // if no file-spec provided, match the file to the regular expression
                            // PERF NOTE: Regex.IsMatch() is an expensive operation, so we avoid it whenever possible
                            recursionState.SearchData.RegexFileMatch.IsMatch(file))
                        {
                            if ((recursionState.SearchData.Filespec == null) ||
                                // if we used a file-spec with a "loosely" defined extension
                                (recursionState.SearchData.ExtensionLengthToEnforce == 0) ||
                                // discard all files that do not have extensions of the desired length
                                (Path.GetExtension(file).Length == recursionState.SearchData.ExtensionLengthToEnforce))
                            {
                                listOfFiles.Add(file);
                            }
                        }
                    }
                    ret.Files = listOfFiles.ToArray(); 
                }
                else
                {
                    ret.Files = files;
                }
            }

            /*
             * Recurse into subdirectories.
             */
            if (recursionState.SearchData.NeedsRecursion && recursionState.RemainingWildcardDirectory.Length > 0)
            {
                // Find the next directory piece.
                string pattern = null;

                if (!IsRecursiveDirectoryMatch(recursionState.RemainingWildcardDirectory))
                {
                    int indexOfNextSlash = recursionState.RemainingWildcardDirectory.IndexOfAny(directorySeparatorCharacters);
                    ErrorUtilities.VerifyThrow(indexOfNextSlash != -1, "Slash should be guaranteed.");

                    pattern = recursionState.RemainingWildcardDirectory.Substring(0, indexOfNextSlash);

                    if (pattern == recursiveDirectoryMatch)
                    {
                        // If pattern turned into **, then there's no choice but to enumerate everything.
                        pattern = null;
                        recursionState.RemainingWildcardDirectory = recursiveDirectoryMatch;
                    }
                    else
                    {
                        // Peel off the leftmost directory piece. So for example, if remainingWildcardDirectory
                        // contains:
                        //
                        //        ?emp\foo\**\bar
                        //
                        // then put '?emp' into pattern. Then put the remaining part,
                        //
                        //        foo\**\bar
                        //
                        // back into remainingWildcardDirectory.
                        // This is a performance optimization. We don't want to enumerate everything if we 
                        // don't have to.
                        recursionState.RemainingWildcardDirectory = recursionState.RemainingWildcardDirectory.Substring(indexOfNextSlash + 1);
                    }
                }

                ret.RemainingWildcardDirectory = recursionState.RemainingWildcardDirectory;
                ret.Subdirs = getFileSystemEntries(FileSystemEntity.Directories, recursionState.BaseDirectory, pattern, null, false);
            }

            return ret;
        }
Beispiel #2
0
        /// <summary>
        /// Get all files that match either the file-spec or the regular expression. 
        /// </summary>
        /// <param name="listOfFiles">List of files that gets populated.</param>
        /// <param name="recursionState">Information about the search</param>
        /// <param name="projectDirectory"></param>
        /// <param name="stripProjectDirectory"></param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        /// <param name="searchesToExclude">Patterns to exclude from the results</param>
        /// <param name="searchesToExcludeInSubdirs">exclude patterns that might activate farther down the directory tree. Keys assume paths are normalized with forward slashes and no trailing slashes</param>
        private static void GetFilesRecursive
        (
            IList<string> listOfFiles,
            RecursionState recursionState,
            string projectDirectory,
            bool stripProjectDirectory,
            GetFileSystemEntries getFileSystemEntries,
            IList<RecursionState> searchesToExclude,
            Dictionary<string, List<RecursionState>> searchesToExcludeInSubdirs
        )
        {
            ErrorUtilities.VerifyThrow((recursionState.SearchData.Filespec== null) || (recursionState.SearchData.RegexFileMatch == null),
                "File-spec overrides the regular expression -- pass null for file-spec if you want to use the regular expression.");

            ErrorUtilities.VerifyThrow((recursionState.SearchData.Filespec != null) || (recursionState.SearchData.RegexFileMatch != null),
                "Need either a file-spec or a regular expression to match files.");

            ErrorUtilities.VerifyThrow(recursionState.RemainingWildcardDirectory != null, "Expected non-null remaning wildcard directory.");

            //  Determine if any of searchesToExclude is necessarily a superset of the results that will be returned.
            //  This means all results will be excluded and we should bail out now.
            if (searchesToExclude != null)
            {
                foreach (var searchToExclude in searchesToExclude)
                {
                    //  The BaseDirectory of all the exclude searches should be the same as the include one
                    Debug.Assert(FileUtilities.PathsEqual(searchToExclude.BaseDirectory, recursionState.BaseDirectory), "Expected exclude search base directory to match include search base directory");

                    //  We can exclude all results in this folder if:
                    if (
                        //  We are matching files based on a filespec and not a regular expression
                        searchToExclude.SearchData.Filespec != null &&
                        //  The wildcard path portion of the excluded search matches the include search
                        FileUtilities.PathsEqual(searchToExclude.RemainingWildcardDirectory, recursionState.RemainingWildcardDirectory) &&
                        //  The exclude search will match ALL filenames OR
                        (searchToExclude.SearchData.Filespec == "*" || searchToExclude.SearchData.Filespec == "*.*" ||
                            //  The exclude search filename pattern matches the include search's pattern
                            (searchToExclude.SearchData.Filespec == recursionState.SearchData.Filespec &&
                            searchToExclude.SearchData.ExtensionLengthToEnforce == recursionState.SearchData.ExtensionLengthToEnforce)))
                    {
                        //  We won't get any results from this search that we would end up keeping
                        return;
                    }
                }
            }

            RecursiveStepResult nextStep = GetFilesRecursiveStep(
                recursionState,
                projectDirectory,
                stripProjectDirectory,
                getFileSystemEntries);

            RecursiveStepResult[] excludeNextSteps = null;
            if (searchesToExclude != null)
            {
                excludeNextSteps = new RecursiveStepResult[searchesToExclude.Count];
                for (int i = 0; i < searchesToExclude.Count; i++)
                {
                    excludeNextSteps[i] = GetFilesRecursiveStep(
                        searchesToExclude[i],
                        projectDirectory,
                        stripProjectDirectory,
                        getFileSystemEntries);
                }
            }

            if (nextStep.Files != null)
            {
                HashSet<string> filesToExclude = null;
                if (excludeNextSteps != null)
                {
                    filesToExclude = new HashSet<string>();
                    foreach (var excludeStep in excludeNextSteps)
                    {
                        foreach (var file in excludeStep.Files)
                        {
                            filesToExclude.Add(file);
                        }
                    }
                }

                foreach (var file in nextStep.Files)
                {
                    if (filesToExclude == null || !filesToExclude.Contains(file))
                    {
                        listOfFiles.Add(file);
                    }
                }
            }

            if (nextStep.Subdirs != null)
            {
                foreach (string subdir in nextStep.Subdirs)
                {
                    //  RecursionState is a struct so this copies it
                    var newRecursionState = recursionState;

                    newRecursionState.BaseDirectory = subdir;
                    newRecursionState.RemainingWildcardDirectory = nextStep.RemainingWildcardDirectory;

                    List<RecursionState> newSearchesToExclude = null;

                    if (excludeNextSteps != null)
                    {
                        newSearchesToExclude = new List<RecursionState>();

                        for (int i = 0; i < excludeNextSteps.Length; i++)
                        {
                            if (excludeNextSteps[i].Subdirs != null &&
                                excludeNextSteps[i].Subdirs.Any(excludedDir => FileUtilities.PathsEqual(excludedDir, subdir)))
                            {
                                RecursionState thisExcludeStep = searchesToExclude[i];
                                thisExcludeStep.BaseDirectory = subdir;
                                thisExcludeStep.RemainingWildcardDirectory = excludeNextSteps[i].RemainingWildcardDirectory;
                                newSearchesToExclude.Add(thisExcludeStep);
                            }
                        }
                    }

                    if (searchesToExcludeInSubdirs != null)
                    {
                        List<RecursionState> searchesForSubdir;

                        // The normalization fixes https://github.com/Microsoft/msbuild/issues/917
                        // and is a partial fix for https://github.com/Microsoft/msbuild/issues/724
                        if (searchesToExcludeInSubdirs.TryGetValue(subdir.NormalizeForPathComparison(), out searchesForSubdir))
                        {
                            //  We've found the base directory that these exclusions apply to.  So now add them as normal searches
                            if (newSearchesToExclude == null)
                            {
                                newSearchesToExclude = new List<RecursionState>();
                            }
                            newSearchesToExclude.AddRange(searchesForSubdir);
                        }
                    }

                    // We never want to strip the project directory from the leaves, because the current 
                    // process directory maybe different
                    GetFilesRecursive(
                        listOfFiles,
                        newRecursionState,
                        projectDirectory,
                        stripProjectDirectory,
                        getFileSystemEntries,
                        newSearchesToExclude,
                        searchesToExcludeInSubdirs);
                }
            }
        }