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

            /*
             * 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 (recursionState.RemainingWildcardDirectory != recursiveDirectoryMatch &&
                    recursionState.RemainingWildcardDirectory != recursiveDirectoryMatch + s_directorySeparator)
                {
                    int indexOfNextSlash = recursionState.RemainingWildcardDirectory.IndexOfAny(directorySeparatorCharacters);
                    ErrorUtilities.VerifyThrow(indexOfNextSlash != -1, "Slash should be guaranteed.");

                    // 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.
                    pattern = recursionState.RemainingWildcardDirectory.Substring(0, indexOfNextSlash);
                    recursionState.RemainingWildcardDirectory = recursionState.RemainingWildcardDirectory.Substring(indexOfNextSlash + 1);

                    // If pattern turned into **, then there's no choice but to enumerate everything.
                    if (pattern == recursiveDirectoryMatch)
                    {
                        pattern = null;
                        recursionState.RemainingWildcardDirectory = recursiveDirectoryMatch;
                    }
                }

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

            return ret;
        }
Example #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. Assumes no trailing slashes</param>
        private static void GetFilesRecursive
        (
            System.Collections.IList 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(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
                        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;
                    }
                }
            }

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

            FileSearchRecursionResult[] excludeNextSteps = null;
            if (searchesToExclude != null)
            {
                excludeNextSteps = new FileSearchRecursionResult[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 => excludedDir.Equals(subdir, StringComparison.Ordinal)))
                            {
                                RecursionState thisExcludeStep = searchesToExclude[i];
                                thisExcludeStep.BaseDirectory = subdir;
                                thisExcludeStep.RemainingWildcardDirectory = excludeNextSteps[i].RemainingWildcardDirectory;
                                newSearchesToExclude.Add(thisExcludeStep);
                            }
                        }
                    }

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

                        if (searchesToExcludeInSubdirs.TryGetValue(subdir, 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);
                }
            }
        }