Example #1
0
        internal static string GetLongPathName(string path, GetFileSystemEntries getFileSystemEntries)
        {
            string str;

            if (path.IndexOf("~", StringComparison.Ordinal) == -1)
            {
                return(path);
            }
            Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(!HasWildcards(path), "GetLongPathName does not handle wildcards and was passed '{0}'.", path);
            string[] strArray = path.Split(directorySeparatorCharacters);
            int      num      = 0;

            if (path.StartsWith(directorySeparator + directorySeparator, StringComparison.Ordinal))
            {
                str = ((directorySeparator + directorySeparator) + strArray[2] + directorySeparator) + strArray[3] + directorySeparator;
                num = 4;
            }
            else if ((path.Length > 2) && (path[1] == ':'))
            {
                str = strArray[0] + directorySeparator;
                num = 1;
            }
            else
            {
                str = string.Empty;
                num = 0;
            }
            string[] strArray2 = new string[strArray.Length - num];
            string   str2      = str;

            for (int i = num; i < strArray.Length; i++)
            {
                if (strArray[i].Length == 0)
                {
                    strArray2[i - num] = string.Empty;
                }
                else if (strArray[i].IndexOf("~", StringComparison.Ordinal) == -1)
                {
                    strArray2[i - num] = strArray[i];
                    str2 = Path.Combine(str2, strArray[i]);
                }
                else
                {
                    string[] strArray3 = getFileSystemEntries(FileSystemEntity.FilesAndDirectories, str2, strArray[i], null, false);
                    if (strArray3.Length == 0)
                    {
                        for (int j = i; j < strArray.Length; j++)
                        {
                            strArray2[j - num] = strArray[j];
                        }
                        break;
                    }
                    Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(strArray3.Length == 1, "Unexpected number of entries ({3}) found when enumerating '{0}' under '{1}'. Original path was '{2}'", strArray[i], str2, path, strArray3.Length);
                    str2 = strArray3[0];
                    strArray2[i - num] = Path.GetFileName(str2);
                }
            }
            return(str + string.Join(directorySeparator, strArray2));
        }
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="baseDirectory">The path to enumerate</param>
        /// <param name="remainingWildcardDirectory">The remaining, wildcard part of the directory.</param>
        /// <param name="filespec">The filespec.</param>
        /// <param name="extensionLengthToEnforce"></param>
        /// <param name="regexFileMatch">Wild-card matching.</param>
        /// <param name="needsRecursion">If true, then recursion is required.</param>
        /// <param name="projectDirectory"></param>
        /// <param name="stripProjectDirectory"></param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        private static void GetFilesRecursive
        (
            System.Collections.IList listOfFiles,
            string baseDirectory,
            string remainingWildcardDirectory,
            string filespec,                // can be null
            int extensionLengthToEnforce,   // only relevant when filespec is not null
            Regex regexFileMatch,           // can be null
            bool needsRecursion,
            string projectDirectory,
            bool stripProjectDirectory,
            GetFileSystemEntries getFileSystemEntries
        )
        {
            ErrorUtilities.VerifyThrow((filespec == null) || (regexFileMatch == null),
                "File-spec overrides the regular expression -- pass null for file-spec if you want to use the regular expression.");

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

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

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

            // Only consider files if...
            if (remainingWildcardDirectory.Length == 0)
            {
                // We've reached the end of the wildcard directory elements.
                considerFiles = true;
            }
            else if (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, baseDirectory, filespec, projectDirectory, stripProjectDirectory);
                foreach (string file in files)
                {
                    if ((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
                        regexFileMatch.IsMatch(file))
                    {
                        if ((filespec == null) ||
                            // if we used a file-spec with a "loosely" defined extension
                            (extensionLengthToEnforce == 0) ||
                            // discard all files that do not have extensions of the desired length
                            (Path.GetExtension(file).Length == extensionLengthToEnforce))
                        {
                            listOfFiles.Add((object)file);
                        }
                    }
                }
            }

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

                if (remainingWildcardDirectory != recursiveDirectoryMatch)
                {
                    int indexOfNextSlash = 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 = remainingWildcardDirectory.Substring(0, indexOfNextSlash);
                    remainingWildcardDirectory = remainingWildcardDirectory.Substring(indexOfNextSlash + 1);

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

                // We never want to strip the project directory from the leaves, because the current 
                // process directory maybe different
                string[] subdirs = getFileSystemEntries(FileSystemEntity.Directories, baseDirectory, pattern, null, false);
                foreach (string subdir in subdirs)
                {
                    GetFilesRecursive(listOfFiles, subdir, remainingWildcardDirectory, filespec, extensionLengthToEnforce, regexFileMatch, true, projectDirectory, stripProjectDirectory, getFileSystemEntries);
                }
            }
        }
Example #3
0
        /// <summary>
        /// Given a filespec, split it into left-most 'fixed' dir part, middle 'wildcard' dir part, and filename part.
        /// The filename part may have wildcard characters in it.
        /// </summary>
        /// <param name="filespec">The filespec to be decomposed.</param>
        /// <param name="fixedDirectoryPart">Receives the fixed directory part.</param>
        /// <param name="wildcardDirectoryPart">The wildcard directory part.</param>
        /// <param name="filenamePart">The filename part.</param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        internal static void SplitFileSpec
        (
            string filespec,
            out string fixedDirectoryPart,
            out string wildcardDirectoryPart,
            out string filenamePart,
            GetFileSystemEntries getFileSystemEntries
        )
        {
            PreprocessFileSpecForSplitting
            (
                filespec,
                out fixedDirectoryPart,
                out wildcardDirectoryPart,
                out filenamePart
            );

            /* 
             * Handle the special case in which filenamePart is '**'.
             * In this case, filenamePart becomes '*.*' and the '**' is appended
             * to the end of the wildcardDirectory part.
             * This is so that later regular expression matching can accurately
             * pull out the different parts (fixed, wildcard, filename) of given
             * file specs.
             */
            if (recursiveDirectoryMatch == filenamePart)
            {
                wildcardDirectoryPart += recursiveDirectoryMatch;
                wildcardDirectoryPart += s_directorySeparator;
                filenamePart = "*.*";
            }

            fixedDirectoryPart = FileMatcher.GetLongPathName(fixedDirectoryPart, getFileSystemEntries);
        }
Example #4
0
        /// <summary>
        /// Given a path name, get its long version.
        /// </summary>
        /// <param name="path">The short path.</param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        /// <returns>The long path.</returns>
        internal static string GetLongPathName
        (
            string path,
            GetFileSystemEntries getFileSystemEntries
        )
        {
            if (path.IndexOf("~", StringComparison.Ordinal) == -1)
            {
                // A path with no '~' must not be a short name.
                return path;
            }

            ErrorUtilities.VerifyThrow(!HasWildcards(path),
                "GetLongPathName does not handle wildcards and was passed '{0}'.", path);

            string[] parts = path.Split(directorySeparatorCharacters);
            string pathRoot;
            int startingElement = 0;

            bool isUnc = path.StartsWith(s_directorySeparator + s_directorySeparator, StringComparison.Ordinal);
            if (isUnc)
            {
                pathRoot = s_directorySeparator + s_directorySeparator;
                pathRoot += parts[2];
                pathRoot += s_directorySeparator;
                pathRoot += parts[3];
                pathRoot += s_directorySeparator;
                startingElement = 4;
            }
            else
            {
                // Is it relative?
                if (path.Length > 2 && path[1] == ':')
                {
                    // Not relative
                    pathRoot = parts[0] + s_directorySeparator;
                    startingElement = 1;
                }
                else
                {
                    // Relative
                    pathRoot = String.Empty;
                    startingElement = 0;
                }
            }

            // Build up an array of parts. These elements may be "" if there are
            // extra slashes.
            string[] longParts = new string[parts.Length - startingElement];

            string longPath = pathRoot;
            for (int i = startingElement; i < parts.Length; ++i)
            {
                // If there is a zero-length part, then that means there was an extra slash.
                if (parts[i].Length == 0)
                {
                    longParts[i - startingElement] = String.Empty;
                }
                else
                {
                    if (parts[i].IndexOf("~", StringComparison.Ordinal) == -1)
                    {
                        // If there's no ~, don't hit the disk.
                        longParts[i - startingElement] = parts[i];
                        longPath = Path.Combine(longPath, parts[i]);
                    }
                    else
                    {
                        // getFileSystemEntries(...) returns an empty array if longPath doesn't exist.
                        string[] entries = getFileSystemEntries(FileSystemEntity.FilesAndDirectories, longPath, parts[i], null, false);

                        if (0 == entries.Length)
                        {
                            // The next part doesn't exist. Therefore, no more of the path will exist.
                            // Just return the rest.
                            for (int j = i; j < parts.Length; ++j)
                            {
                                longParts[j - startingElement] = parts[j];
                            }
                            break;
                        }

                        // Since we know there are no wild cards, this should be length one.
                        ErrorUtilities.VerifyThrow(entries.Length == 1,
                            "Unexpected number of entries ({3}) found when enumerating '{0}' under '{1}'. Original path was '{2}'",
                            parts[i], longPath, path, entries.Length);

                        // Entries[0] contains the full path.
                        longPath = entries[0];

                        // We just want the trailing node.
                        longParts[i - startingElement] = Path.GetFileName(longPath);
                    }
                }
            }

            return pathRoot + String.Join(s_directorySeparator, longParts);
        }
Example #5
0
        static SearchAction GetFileSearchData(string projectDirectoryUnescaped, string filespecUnescaped,
            GetFileSystemEntries getFileSystemEntries, DirectoryExists directoryExists, out bool stripProjectDirectory,
            out RecursionState result)
        {
            stripProjectDirectory = false;
            result = new RecursionState();

            string fixedDirectoryPart;
            string wildcardDirectoryPart;
            string filenamePart;
            string matchFileExpression;
            bool needsRecursion;
            bool isLegalFileSpec;
            GetFileSpecInfo
            (
                filespecUnescaped,
                out fixedDirectoryPart,
                out wildcardDirectoryPart,
                out filenamePart,
                out matchFileExpression,
                out needsRecursion,
                out isLegalFileSpec,
                getFileSystemEntries
            );

            /*
             * If the filespec is invalid, then just return now.
             */
            if (!isLegalFileSpec)
            {
                return SearchAction.ReturnFileSpec;
            }

            // The projectDirectory is not null only if we are running the evaluation from
            // inside the engine (i.e. not from a task)
            if (projectDirectoryUnescaped != null)
            {
                if (fixedDirectoryPart != null)
                {
                    string oldFixedDirectoryPart = fixedDirectoryPart;
                    try
                    {
                        fixedDirectoryPart = Path.Combine(projectDirectoryUnescaped, fixedDirectoryPart);
                    }
                    catch (ArgumentException)
                    {
                        return SearchAction.ReturnEmptyList;
                    }

                    stripProjectDirectory = !String.Equals(fixedDirectoryPart, oldFixedDirectoryPart, StringComparison.OrdinalIgnoreCase);
                }
                else
                {
                    fixedDirectoryPart = projectDirectoryUnescaped;
                    stripProjectDirectory = true;
                }
            }

            /*
             * If the fixed directory part doesn't exist, then this means no files should be
             * returned.
             */
            if (fixedDirectoryPart.Length > 0 && !directoryExists(fixedDirectoryPart))
            {
                return SearchAction.ReturnEmptyList;
            }

            // determine if we need to use the regular expression to match the files
            // PERF NOTE: Constructing a Regex object is expensive, so we avoid it whenever possible
            bool matchWithRegex =
                // if we have a directory specification that uses wildcards, and
                (wildcardDirectoryPart.Length > 0) &&
                // the specification is not a simple "**"
                !IsRecursiveDirectoryMatch(wildcardDirectoryPart);
            // then we need to use the regular expression

            // if we're not using the regular expression, get the file pattern extension
            string extensionPart = matchWithRegex
                ? null
                : Path.GetExtension(filenamePart);

            // check if the file pattern would cause Windows to match more loosely on the extension
            // NOTE: Windows matches loosely in two cases (in the absence of the * wildcard in the extension):
            // 1) if the extension ends with the ? wildcard, it matches files with shorter extensions also e.g. "file.tx?" would
            //    match both "file.txt" and "file.tx"
            // 2) if the extension is three characters, and the filename contains the * wildcard, it matches files with longer
            //    extensions that start with the same three characters e.g. "*.htm" would match both "file.htm" and "file.html"
            bool needToEnforceExtensionLength =
                    (extensionPart != null) &&
                    (extensionPart.IndexOf('*') == -1)
                &&
                    (extensionPart.EndsWith("?", StringComparison.Ordinal)
                ||
                    ((extensionPart.Length == (3 + 1 /* +1 for the period */)) &&
                    (filenamePart.IndexOf('*') != -1)));

            var searchData = new FilesSearchData(
                // if using the regular expression, ignore the file pattern
                (matchWithRegex ? null : filenamePart), (needToEnforceExtensionLength ? extensionPart.Length : 0),
                // if using the file pattern, ignore the regular expression
                (matchWithRegex ? new Regex(matchFileExpression, RegexOptions.IgnoreCase) : null),
                needsRecursion);

            result.SearchData = searchData;
            result.BaseDirectory = fixedDirectoryPart;
            result.RemainingWildcardDirectory = wildcardDirectoryPart;

            return SearchAction.RunSearch;
        }
Example #6
0
 private static void GetFileSpecInfo(string filespec, out string fixedDirectoryPart, out string wildcardDirectoryPart, out string filenamePart, out string matchFileExpression, out bool needsRecursion, out bool isLegalFileSpec, GetFileSystemEntries getFileSystemEntries)
 {
     isLegalFileSpec       = true;
     needsRecursion        = false;
     fixedDirectoryPart    = string.Empty;
     wildcardDirectoryPart = string.Empty;
     filenamePart          = string.Empty;
     matchFileExpression   = null;
     if (-1 != filespec.IndexOfAny(Path.GetInvalidPathChars()))
     {
         isLegalFileSpec = false;
     }
     else if (-1 != filespec.IndexOf("...", StringComparison.Ordinal))
     {
         isLegalFileSpec = false;
     }
     else
     {
         int num = filespec.LastIndexOf(":", StringComparison.Ordinal);
         if ((-1 != num) && (1 != num))
         {
             isLegalFileSpec = false;
         }
         else
         {
             SplitFileSpec(filespec, out fixedDirectoryPart, out wildcardDirectoryPart, out filenamePart, getFileSystemEntries);
             matchFileExpression = RegularExpressionFromFileSpec(fixedDirectoryPart, wildcardDirectoryPart, filenamePart, out isLegalFileSpec);
             if (isLegalFileSpec)
             {
                 needsRecursion = wildcardDirectoryPart.Length != 0;
             }
         }
     }
 }
 private static void GetFileSpecInfo(string filespec, out string fixedDirectoryPart, out string wildcardDirectoryPart, out string filenamePart, out string matchFileExpression, out bool needsRecursion, out bool isLegalFileSpec, GetFileSystemEntries getFileSystemEntries)
 {
     isLegalFileSpec = true;
     needsRecursion = false;
     fixedDirectoryPart = string.Empty;
     wildcardDirectoryPart = string.Empty;
     filenamePart = string.Empty;
     matchFileExpression = null;
     if (-1 != filespec.IndexOfAny(Path.GetInvalidPathChars()))
     {
         isLegalFileSpec = false;
     }
     else if (-1 != filespec.IndexOf("...", StringComparison.Ordinal))
     {
         isLegalFileSpec = false;
     }
     else
     {
         int num = filespec.LastIndexOf(":", StringComparison.Ordinal);
         if ((-1 != num) && (1 != num))
         {
             isLegalFileSpec = false;
         }
         else
         {
             SplitFileSpec(filespec, out fixedDirectoryPart, out wildcardDirectoryPart, out filenamePart, getFileSystemEntries);
             matchFileExpression = RegularExpressionFromFileSpec(fixedDirectoryPart, wildcardDirectoryPart, filenamePart, out isLegalFileSpec);
             if (isLegalFileSpec)
             {
                 needsRecursion = wildcardDirectoryPart.Length != 0;
             }
         }
     }
 }
Example #8
0
        internal static string[] GetFiles(string projectDirectoryUnescaped, string filespecUnescaped, GetFileSystemEntries getFileSystemEntries, Microsoft.Build.Shared.DirectoryExists directoryExists)
        {
            string str;
            string str2;
            string str3;
            string str4;
            bool   flag;
            bool   flag2;

            if (!HasWildcards(filespecUnescaped))
            {
                return(new string[] { filespecUnescaped });
            }
            ArrayList list        = new ArrayList();
            IList     listOfFiles = list;

            GetFileSpecInfo(filespecUnescaped, out str, out str2, out str3, out str4, out flag, out flag2, getFileSystemEntries);
            if (!flag2)
            {
                return(new string[] { filespecUnescaped });
            }
            bool stripProjectDirectory = false;

            if (projectDirectoryUnescaped != null)
            {
                if (str != null)
                {
                    string b = str;
                    try
                    {
                        str = Path.Combine(projectDirectoryUnescaped, str);
                    }
                    catch (ArgumentException)
                    {
                        return(new string[0]);
                    }
                    stripProjectDirectory = !string.Equals(str, b, StringComparison.OrdinalIgnoreCase);
                }
                else
                {
                    str = projectDirectoryUnescaped;
                    stripProjectDirectory = true;
                }
            }
            if ((str.Length > 0) && !directoryExists(str))
            {
                return(new string[0]);
            }
            bool   flag4 = (str2.Length > 0) && (str2 != ("**" + directorySeparator));
            string str6  = flag4 ? null : Path.GetExtension(str3);
            bool   flag5 = ((str6 != null) && (str6.IndexOf('*') == -1)) && (str6.EndsWith("?", StringComparison.Ordinal) || ((str6.Length == 4) && (str3.IndexOf('*') != -1)));

            GetFilesRecursive(listOfFiles, str, str2, flag4 ? null : str3, flag5 ? str6.Length : 0, flag4 ? new Regex(str4, RegexOptions.IgnoreCase) : null, flag, projectDirectoryUnescaped, stripProjectDirectory, getFileSystemEntries);
            return((string[])list.ToArray(typeof(string)));
        }
 internal static string[] GetFiles(string projectDirectoryUnescaped, string filespecUnescaped, GetFileSystemEntries getFileSystemEntries, Microsoft.Build.Shared.DirectoryExists directoryExists)
 {
     string str;
     string str2;
     string str3;
     string str4;
     bool flag;
     bool flag2;
     if (!HasWildcards(filespecUnescaped))
     {
         return new string[] { filespecUnescaped };
     }
     ArrayList list = new ArrayList();
     IList listOfFiles = list;
     GetFileSpecInfo(filespecUnescaped, out str, out str2, out str3, out str4, out flag, out flag2, getFileSystemEntries);
     if (!flag2)
     {
         return new string[] { filespecUnescaped };
     }
     bool stripProjectDirectory = false;
     if (projectDirectoryUnescaped != null)
     {
         if (str != null)
         {
             string b = str;
             try
             {
                 str = Path.Combine(projectDirectoryUnescaped, str);
             }
             catch (ArgumentException)
             {
                 return new string[0];
             }
             stripProjectDirectory = !string.Equals(str, b, StringComparison.OrdinalIgnoreCase);
         }
         else
         {
             str = projectDirectoryUnescaped;
             stripProjectDirectory = true;
         }
     }
     if ((str.Length > 0) && !directoryExists(str))
     {
         return new string[0];
     }
     bool flag4 = (str2.Length > 0) && (str2 != ("**" + directorySeparator));
     string str6 = flag4 ? null : Path.GetExtension(str3);
     bool flag5 = ((str6 != null) && (str6.IndexOf('*') == -1)) && (str6.EndsWith("?", StringComparison.Ordinal) || ((str6.Length == 4) && (str3.IndexOf('*') != -1)));
     GetFilesRecursive(listOfFiles, str, str2, flag4 ? null : str3, flag5 ? str6.Length : 0, flag4 ? new Regex(str4, RegexOptions.IgnoreCase) : null, flag, projectDirectoryUnescaped, stripProjectDirectory, getFileSystemEntries);
     return (string[]) list.ToArray(typeof(string));
 }
 internal static void GetFileSpecInfo(string filespec, out Regex regexFileMatch, out bool needsRecursion, out bool isLegalFileSpec, GetFileSystemEntries getFileSystemEntries)
 {
     string str;
     string str2;
     string str3;
     string str4;
     GetFileSpecInfo(filespec, out str, out str2, out str3, out str4, out needsRecursion, out isLegalFileSpec, getFileSystemEntries);
     if (isLegalFileSpec)
     {
         regexFileMatch = new Regex(str4, RegexOptions.IgnoreCase);
     }
     else
     {
         regexFileMatch = null;
     }
 }
Example #11
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;
        }
Example #12
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);
                }
            }
        }
Example #13
0
        /// <summary>
        /// Given a filespec, find the files that match. 
        /// Will never throw IO exceptions: if there is no match, returns the input verbatim.
        /// </summary>
        /// <param name="projectDirectoryUnescaped">The project directory.</param>
        /// <param name="filespecUnescaped">Get files that match the given file spec.</param>
        /// <param name="getFileSystemEntries">Get files that match the given file spec.</param>
        /// <param name="directoryExists">Determine whether a directory exists.</param>
        /// <returns>The array of files.</returns>
        internal static string[] GetFiles
        (
            string projectDirectoryUnescaped,
            string filespecUnescaped,
            IEnumerable<string> excludeSpecsUnescaped,
            GetFileSystemEntries getFileSystemEntries,
            DirectoryExists directoryExists
        )
        {
            // For performance. Short-circuit iff there is no wildcard.
            // Perf Note: Doing a [Last]IndexOfAny(...) is much faster than compiling a
            // regular expression that does the same thing, regardless of whether
            // filespec contains one of the characters.
            // Choose LastIndexOfAny instead of IndexOfAny because it seems more likely
            // that wildcards will tend to be towards the right side.
            if (!HasWildcards(filespecUnescaped))
            {
                return CreateArrayWithSingleItemIfNotExcluded(filespecUnescaped, excludeSpecsUnescaped);
            }

            // UNDONE (perf): Short circuit the complex processing when we only have a path and a wildcarded filename

            /*
             * Analyze the file spec and get the information we need to do the matching.
             */
            bool stripProjectDirectory;
            RecursionState state;
            var action = GetFileSearchData(projectDirectoryUnescaped, filespecUnescaped, getFileSystemEntries, directoryExists,
                out stripProjectDirectory, out state);

            if (action == SearchAction.ReturnEmptyList)
            {
                return new string[0];
            }
            else if (action == SearchAction.ReturnFileSpec)
            {
                return CreateArrayWithSingleItemIfNotExcluded(filespecUnescaped, excludeSpecsUnescaped);
            }
            else if (action != SearchAction.RunSearch)
            {
                //  This means the enum value wasn't valid (or a new one was added without updating code correctly)
                throw new NotSupportedException(action.ToString());
            }

            List<RecursionState> searchesToExclude = null;

            //  Exclude searches which will become active when the recursive search reaches their BaseDirectory.
            //  The BaseDirectory of the exclude search is the key for this dictionary.
            Dictionary<string, List<RecursionState>> searchesToExcludeInSubdirs = null;

            HashSet<string> resultsToExclude = null;
            if (excludeSpecsUnescaped != null)
            {
                searchesToExclude = new List<RecursionState>();
                foreach (string excludeSpec in excludeSpecsUnescaped)
                {
                    //  This is ignored, we always use the include pattern's value for stripProjectDirectory
                    bool excludeStripProjectDirectory;

                    RecursionState excludeState;
                    var excludeAction = GetFileSearchData(projectDirectoryUnescaped, excludeSpec, getFileSystemEntries, directoryExists,
                        out excludeStripProjectDirectory, out excludeState);

                    if (excludeAction == SearchAction.ReturnFileSpec)
                    {
                        if (resultsToExclude == null)
                        {
                            resultsToExclude = new HashSet<string>();
                        }
                        resultsToExclude.Add(excludeSpec);
                    }
                    else if (excludeAction == SearchAction.ReturnEmptyList)
                    {
                        //  Nothing to do
                        continue;
                    }
                    else if (excludeAction != SearchAction.RunSearch)
                    {
                        //  This means the enum value wasn't valid (or a new one was added without updating code correctly)
                        throw new NotSupportedException(excludeAction.ToString());
                    }

                    var excludeBaseDirectoryNormalized = excludeState.BaseDirectory.NormalizeForPathComparison();
                    var includeBaseDirectoryNormalized = state.BaseDirectory.NormalizeForPathComparison();

                    if (excludeBaseDirectoryNormalized != includeBaseDirectoryNormalized)
                    {
                        //  What to do if the BaseDirectory for the exclude search doesn't match the one for inclusion?
                        //  - If paths don't match (one isn't a prefix of the other), then ignore the exclude search.  Examples:
                        //      - c:\Foo\ - c:\Bar\
                        //      - c:\Foo\Bar\ - C:\Foo\Baz\
                        //      - c:\Foo\ - c:\Foo2\
                        if (excludeBaseDirectoryNormalized.Length == includeBaseDirectoryNormalized.Length)
                        {
                            //  Same length, but different paths.  Ignore this exclude search
                            continue;
                        }
                        else if (excludeBaseDirectoryNormalized.Length > includeBaseDirectoryNormalized.Length)
                        {
                            if (!excludeBaseDirectoryNormalized.StartsWith(includeBaseDirectoryNormalized))
                            {
                                //  Exclude path is longer, but doesn't start with include path.  So ignore it.
                                continue;
                            }

                            //  - The exclude BaseDirectory is somewhere under the include BaseDirectory. So
                            //    keep the exclude search, but don't do any processing on it while recursing until the baseDirectory
                            //    in the recursion matches the exclude BaseDirectory.  Examples:
                            //      - Include - Exclude
                            //      - C:\git\msbuild\ - c:\git\msbuild\obj\
                            //      - C:\git\msbuild\ - c:\git\msbuild\src\Common\

                            if (searchesToExcludeInSubdirs == null)
                            {
                                searchesToExcludeInSubdirs = new Dictionary<string, List<RecursionState>>();
                            }
                            List<RecursionState> listForSubdir;
                            if (!searchesToExcludeInSubdirs.TryGetValue(excludeBaseDirectoryNormalized, out listForSubdir))
                            {
                                listForSubdir = new List<RecursionState>();

                                // The normalization fixes https://github.com/Microsoft/msbuild/issues/917
                                // and is a partial fix for https://github.com/Microsoft/msbuild/issues/724
                                searchesToExcludeInSubdirs[excludeBaseDirectoryNormalized] = listForSubdir;
                            }
                            listForSubdir.Add(excludeState);
                        }
                        else
                        {
                            //  Exclude base directory length is less than include base directory length.
                            if (!state.BaseDirectory.StartsWith(excludeState.BaseDirectory))
                            {
                                //  Include path is longer, but doesn't start with the exclude path.  So ignore exclude path
                                //  (since it won't match anything under the include path)
                                continue;
                            }

                            //  Now check the wildcard part
                            if (excludeState.RemainingWildcardDirectory.Length == 0)
                            {
                                //  The wildcard part is empty, so ignore the exclude search, as it's looking for files non-recursively
                                //  in a folder higher up than the include baseDirectory.
                                //  Example: include="c:\git\msbuild\src\Framework\**\*.cs" exclude="c:\git\msbuild\*.cs"
                                continue;
                            }
                            else if (IsRecursiveDirectoryMatch(excludeState.RemainingWildcardDirectory))
                            {
                                //  The wildcard part is exactly "**\", so the exclude pattern will apply to everything in the include
                                //  pattern, so simply update the exclude's BaseDirectory to be the same as the include baseDirectory
                                //  Example: include="c:\git\msbuild\src\Framework\**\*.*" exclude="c:\git\msbuild\**\*.bak"
                                excludeState.BaseDirectory = state.BaseDirectory;
                                searchesToExclude.Add(excludeState);
                            }
                            else
                            {
                                //  The wildcard part is non-empty and not "**\", so we will need to match it with a Regex.  Fortunately
                                //  these conditions mean that it needs to be matched with a Regex anyway, so here we will update the
                                //  BaseDirectory to be the same as the exclude BaseDirectory, and change the wildcard part to be "**\"
                                //  because we don't know where the different parts of the exclude wildcard part would be matched.
                                //  Example: include="c:\git\msbuild\src\Framework\**\*.*" exclude="c:\git\msbuild\**\bin\**\*.*"
                                Debug.Assert(excludeState.SearchData.RegexFileMatch != null, "Expected Regex to be used for exclude file matching");
                                excludeState.BaseDirectory = state.BaseDirectory;
                                excludeState.RemainingWildcardDirectory = recursiveDirectoryMatch + s_directorySeparator;
                                searchesToExclude.Add(excludeState);
                            }
                        }
                    }
                    else
                    {
                        searchesToExclude.Add(excludeState);
                    }
                }
            }

            if (searchesToExclude != null && searchesToExclude.Count == 0)
            {
                searchesToExclude = null;
            }

            /*
             * Even though we return a string[] we work internally with an IList.
             * This is because it's cheaper to add items to an IList and this code
             * might potentially do a lot of that.
             */
            var listOfFiles = new List<string>();

            /*
             * Now get the files that match, starting at the lowest fixed directory.
             */
            try
            {
                GetFilesRecursive(
                    listOfFiles,
                    state,
                    projectDirectoryUnescaped,
                    stripProjectDirectory,
                    getFileSystemEntries,
                    searchesToExclude,
                    searchesToExcludeInSubdirs);
            }
            catch (Exception ex) when (ExceptionHandling.IsIoRelatedException(ex))
            {
                // Assume it's not meant to be a path
                return CreateArrayWithSingleItemIfNotExcluded(filespecUnescaped, excludeSpecsUnescaped);
            }

            /*
             * Build the return array.
             */
            var files = resultsToExclude != null
                ? listOfFiles.Where(f => !resultsToExclude.Contains(f)).ToArray()
                : listOfFiles.ToArray();

            return files;
        }
Example #14
0
        /// <summary>
        /// Given a filespec, get the information needed for file matching. 
        /// </summary>
        /// <param name="filespec">The filespec.</param>
        /// <param name="regexFileMatch">Receives the regular expression.</param>
        /// <param name="needsRecursion">Receives the flag that is true if recursion is required.</param>
        /// <param name="isLegalFileSpec">Receives the flag that is true if the filespec is legal.</param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        internal static void GetFileSpecInfo
        (
            string filespec,
            out Regex regexFileMatch,
            out bool needsRecursion,
            out bool isLegalFileSpec,
            GetFileSystemEntries getFileSystemEntries

        )
        {
            string fixedDirectoryPart;
            string wildcardDirectoryPart;
            string filenamePart;
            string matchFileExpression;

            GetFileSpecInfo(filespec,
                out fixedDirectoryPart, out wildcardDirectoryPart, out filenamePart,
                out matchFileExpression, out needsRecursion, out isLegalFileSpec,
                getFileSystemEntries);

            if (isLegalFileSpec)
            {
                regexFileMatch = new Regex(matchFileExpression, RegexOptions.IgnoreCase);
            }
            else
            {
                regexFileMatch = null;
            }
        }
 private static void GetFilesRecursive(IList listOfFiles, string baseDirectory, string remainingWildcardDirectory, string filespec, int extensionLengthToEnforce, Regex regexFileMatch, bool needsRecursion, string projectDirectory, bool stripProjectDirectory, GetFileSystemEntries getFileSystemEntries)
 {
     Microsoft.Build.Shared.ErrorUtilities.VerifyThrow((filespec == null) || (regexFileMatch == null), "File-spec overrides the regular expression -- pass null for file-spec if you want to use the regular expression.");
     Microsoft.Build.Shared.ErrorUtilities.VerifyThrow((filespec != null) || (regexFileMatch != null), "Need either a file-spec or a regular expression to match files.");
     Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(remainingWildcardDirectory != null, "Expected non-null remaning wildcard directory.");
     bool flag = false;
     if (remainingWildcardDirectory.Length == 0)
     {
         flag = true;
     }
     else if (remainingWildcardDirectory.IndexOf("**", StringComparison.Ordinal) == 0)
     {
         flag = true;
     }
     if (flag)
     {
         foreach (string str in getFileSystemEntries(FileSystemEntity.Files, baseDirectory, filespec, projectDirectory, stripProjectDirectory))
         {
             if (((filespec != null) || regexFileMatch.IsMatch(str)) && (((filespec == null) || (extensionLengthToEnforce == 0)) || (Path.GetExtension(str).Length == extensionLengthToEnforce)))
             {
                 listOfFiles.Add(str);
             }
         }
     }
     if (needsRecursion && (remainingWildcardDirectory.Length > 0))
     {
         string pattern = null;
         if (remainingWildcardDirectory != "**")
         {
             int length = remainingWildcardDirectory.IndexOfAny(directorySeparatorCharacters);
             Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(length != -1, "Slash should be guaranteed.");
             pattern = remainingWildcardDirectory.Substring(0, length);
             remainingWildcardDirectory = remainingWildcardDirectory.Substring(length + 1);
             if (pattern == "**")
             {
                 pattern = null;
                 remainingWildcardDirectory = "**";
             }
         }
         foreach (string str3 in getFileSystemEntries(FileSystemEntity.Directories, baseDirectory, pattern, null, false))
         {
             GetFilesRecursive(listOfFiles, str3, remainingWildcardDirectory, filespec, extensionLengthToEnforce, regexFileMatch, true, projectDirectory, stripProjectDirectory, getFileSystemEntries);
         }
     }
 }
Example #16
0
        /// <summary>
        /// Given a filespec, get the information needed for file matching.
        /// </summary>
        /// <param name="filespec">The filespec.</param>
        /// <param name="fixedDirectoryPart">Receives the fixed directory part.</param>
        /// <param name="wildcardDirectoryPart">Receives the wildcard directory part.</param>
        /// <param name="filenamePart">Receives the filename part.</param>
        /// <param name="matchFileExpression">Receives the regular expression.</param>
        /// <param name="needsRecursion">Receives the flag that is true if recursion is required.</param>
        /// <param name="isLegalFileSpec">Receives the flag that is true if the filespec is legal.</param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        private static void GetFileSpecInfo
        (
            string filespec,
            out string fixedDirectoryPart,
            out string wildcardDirectoryPart,
            out string filenamePart,
            out string matchFileExpression,
            out bool needsRecursion,
            out bool isLegalFileSpec,
            GetFileSystemEntries getFileSystemEntries
        )
        {
            isLegalFileSpec = true;
            needsRecursion = false;
            fixedDirectoryPart = String.Empty;
            wildcardDirectoryPart = String.Empty;
            filenamePart = String.Empty;
            matchFileExpression = null;

            // bail out if filespec contains illegal characters
            if (-1 != filespec.IndexOfAny(s_invalidPathChars))
            {
                isLegalFileSpec = false;
                return;
            }

            /*
             * Check for patterns in the filespec that are explicitly illegal.
             * 
             * Any path with "..." in it is illegal.
             */
            if (-1 != filespec.IndexOf("...", StringComparison.Ordinal))
            {
                isLegalFileSpec = false;
                return;
            }

            /*
             * If there is a ':' anywhere but the second character, this is an illegal pattern.
             * Catches this case among others,
             * 
             *        http://www.website.com
             * 
             */
            int rightmostColon = filespec.LastIndexOf(":", StringComparison.Ordinal);

            if
            (
                -1 != rightmostColon
                && 1 != rightmostColon
            )
            {
                isLegalFileSpec = false;
                return;
            }

            /*
             * Now break up the filespec into constituent parts--fixed, wildcard and filename.
             */
            SplitFileSpec(filespec, out fixedDirectoryPart, out wildcardDirectoryPart, out filenamePart, getFileSystemEntries);

            /*
             *  Get a regular expression for matching files that will be found.
             */
            matchFileExpression = RegularExpressionFromFileSpec(fixedDirectoryPart, wildcardDirectoryPart, filenamePart, out isLegalFileSpec);

            /*
             * Was the filespec valid? If not, then just return now.
             */
            if (!isLegalFileSpec)
            {
                return;
            }

            /*
             * Determine whether recursion will be required.
             */
            needsRecursion = (wildcardDirectoryPart.Length != 0);
        }
 internal static string GetLongPathName(string path, GetFileSystemEntries getFileSystemEntries)
 {
     string str;
     if (path.IndexOf("~", StringComparison.Ordinal) == -1)
     {
         return path;
     }
     Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(!HasWildcards(path), "GetLongPathName does not handle wildcards and was passed '{0}'.", path);
     string[] strArray = path.Split(directorySeparatorCharacters);
     int num = 0;
     if (path.StartsWith(directorySeparator + directorySeparator, StringComparison.Ordinal))
     {
         str = ((directorySeparator + directorySeparator) + strArray[2] + directorySeparator) + strArray[3] + directorySeparator;
         num = 4;
     }
     else if ((path.Length > 2) && (path[1] == ':'))
     {
         str = strArray[0] + directorySeparator;
         num = 1;
     }
     else
     {
         str = string.Empty;
         num = 0;
     }
     string[] strArray2 = new string[strArray.Length - num];
     string str2 = str;
     for (int i = num; i < strArray.Length; i++)
     {
         if (strArray[i].Length == 0)
         {
             strArray2[i - num] = string.Empty;
         }
         else if (strArray[i].IndexOf("~", StringComparison.Ordinal) == -1)
         {
             strArray2[i - num] = strArray[i];
             str2 = Path.Combine(str2, strArray[i]);
         }
         else
         {
             string[] strArray3 = getFileSystemEntries(FileSystemEntity.FilesAndDirectories, str2, strArray[i], null, false);
             if (strArray3.Length == 0)
             {
                 for (int j = i; j < strArray.Length; j++)
                 {
                     strArray2[j - num] = strArray[j];
                 }
                 break;
             }
             Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(strArray3.Length == 1, "Unexpected number of entries ({3}) found when enumerating '{0}' under '{1}'. Original path was '{2}'", strArray[i], str2, path, strArray3.Length);
             str2 = strArray3[0];
             strArray2[i - num] = Path.GetFileName(str2);
         }
     }
     return (str + string.Join(directorySeparator, strArray2));
 }
Example #18
0
        internal static void GetFileSpecInfo(string filespec, out Regex regexFileMatch, out bool needsRecursion, out bool isLegalFileSpec, GetFileSystemEntries getFileSystemEntries)
        {
            string str;
            string str2;
            string str3;
            string str4;

            GetFileSpecInfo(filespec, out str, out str2, out str3, out str4, out needsRecursion, out isLegalFileSpec, getFileSystemEntries);
            if (isLegalFileSpec)
            {
                regexFileMatch = new Regex(str4, RegexOptions.IgnoreCase);
            }
            else
            {
                regexFileMatch = null;
            }
        }
 internal static void SplitFileSpec(string filespec, out string fixedDirectoryPart, out string wildcardDirectoryPart, out string filenamePart, GetFileSystemEntries getFileSystemEntries)
 {
     PreprocessFileSpecForSplitting(filespec, out fixedDirectoryPart, out wildcardDirectoryPart, out filenamePart);
     if ("**" == filenamePart)
     {
         wildcardDirectoryPart = wildcardDirectoryPart + "**";
         wildcardDirectoryPart = wildcardDirectoryPart + directorySeparator;
         filenamePart = "*.*";
     }
     fixedDirectoryPart = GetLongPathName(fixedDirectoryPart, getFileSystemEntries);
 }
Example #20
0
        private static void GetFilesRecursive(IList listOfFiles, string baseDirectory, string remainingWildcardDirectory, string filespec, int extensionLengthToEnforce, Regex regexFileMatch, bool needsRecursion, string projectDirectory, bool stripProjectDirectory, GetFileSystemEntries getFileSystemEntries)
        {
            Microsoft.Build.Shared.ErrorUtilities.VerifyThrow((filespec == null) || (regexFileMatch == null), "File-spec overrides the regular expression -- pass null for file-spec if you want to use the regular expression.");
            Microsoft.Build.Shared.ErrorUtilities.VerifyThrow((filespec != null) || (regexFileMatch != null), "Need either a file-spec or a regular expression to match files.");
            Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(remainingWildcardDirectory != null, "Expected non-null remaning wildcard directory.");
            bool flag = false;

            if (remainingWildcardDirectory.Length == 0)
            {
                flag = true;
            }
            else if (remainingWildcardDirectory.IndexOf("**", StringComparison.Ordinal) == 0)
            {
                flag = true;
            }
            if (flag)
            {
                foreach (string str in getFileSystemEntries(FileSystemEntity.Files, baseDirectory, filespec, projectDirectory, stripProjectDirectory))
                {
                    if (((filespec != null) || regexFileMatch.IsMatch(str)) && (((filespec == null) || (extensionLengthToEnforce == 0)) || (Path.GetExtension(str).Length == extensionLengthToEnforce)))
                    {
                        listOfFiles.Add(str);
                    }
                }
            }
            if (needsRecursion && (remainingWildcardDirectory.Length > 0))
            {
                string pattern = null;
                if (remainingWildcardDirectory != "**")
                {
                    int length = remainingWildcardDirectory.IndexOfAny(directorySeparatorCharacters);
                    Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(length != -1, "Slash should be guaranteed.");
                    pattern = remainingWildcardDirectory.Substring(0, length);
                    remainingWildcardDirectory = remainingWildcardDirectory.Substring(length + 1);
                    if (pattern == "**")
                    {
                        pattern = null;
                        remainingWildcardDirectory = "**";
                    }
                }
                foreach (string str3 in getFileSystemEntries(FileSystemEntity.Directories, baseDirectory, pattern, null, false))
                {
                    GetFilesRecursive(listOfFiles, str3, remainingWildcardDirectory, filespec, extensionLengthToEnforce, regexFileMatch, true, projectDirectory, stripProjectDirectory, getFileSystemEntries);
                }
            }
        }
Example #21
0
        /// <summary>
        /// Given a filespec, find the files that match. 
        /// Will never throw IO exceptions: if there is no match, returns the input verbatim.
        /// </summary>
        /// <param name="projectDirectoryUnescaped">The project directory.</param>
        /// <param name="filespecUnescaped">Get files that match the given file spec.</param>
        /// <param name="getFileSystemEntries">Get files that match the given file spec.</param>
        /// <param name="directoryExists">Determine whether a directory exists.</param>
        /// <returns>The array of files.</returns>
        internal static string[] GetFiles
        (
            string projectDirectoryUnescaped,
            string filespecUnescaped,
            GetFileSystemEntries getFileSystemEntries,
            DirectoryExists directoryExists
        )
        {
            // For performance. Short-circuit iff there is no wildcard.
            // Perf Note: Doing a [Last]IndexOfAny(...) is much faster than compiling a
            // regular expression that does the same thing, regardless of whether
            // filespec contains one of the characters.
            // Choose LastIndexOfAny instead of IndexOfAny because it seems more likely
            // that wildcards will tend to be towards the right side.
            if (!HasWildcards(filespecUnescaped))
            {
                return new string[] { filespecUnescaped };
            }

            // UNDONE (perf): Short circuit the complex processing when we only have a path and a wildcarded filename

            /*
             * Even though we return a string[] we work internally with an IList.
             * This is because it's cheaper to add items to an IList and this code
             * might potentially do a lot of that.
             */
            System.Collections.ArrayList arrayListOfFiles = new System.Collections.ArrayList();
            System.Collections.IList listOfFiles = (System.Collections.IList)arrayListOfFiles;

            /*
             * Analyze the file spec and get the information we need to do the matching.
             */
            string fixedDirectoryPart;
            string wildcardDirectoryPart;
            string filenamePart;
            string matchFileExpression;
            bool needsRecursion;
            bool isLegalFileSpec;
            GetFileSpecInfo
            (
                filespecUnescaped,
                out fixedDirectoryPart,
                out wildcardDirectoryPart,
                out filenamePart,
                out matchFileExpression,
                out needsRecursion,
                out isLegalFileSpec,
                getFileSystemEntries
            );

            /*
             * If the filespec is invalid, then just return now.
             */
            if (!isLegalFileSpec)
            {
                return new string[] { filespecUnescaped };
            }

            // The projectDirectory is not null only if we are running the evaluation from
            // inside the engine (i.e. not from a task)
            bool stripProjectDirectory = false;
            if (projectDirectoryUnescaped != null)
            {
                if (fixedDirectoryPart != null)
                {
                    string oldFixedDirectoryPart = fixedDirectoryPart;
                    try
                    {
                        fixedDirectoryPart = Path.Combine(projectDirectoryUnescaped, fixedDirectoryPart);
                    }
                    catch (ArgumentException)
                    {
                        return new string[0];
                    }

                    stripProjectDirectory = !String.Equals(fixedDirectoryPart, oldFixedDirectoryPart, StringComparison.OrdinalIgnoreCase);
                }
                else
                {
                    fixedDirectoryPart = projectDirectoryUnescaped;
                    stripProjectDirectory = true;
                }
            }

            /*
             * If the fixed directory part doesn't exist, then this means no files should be
             * returned.
             */
            if (fixedDirectoryPart.Length > 0 && !directoryExists(fixedDirectoryPart))
            {
                return new string[0];
            }

            // determine if we need to use the regular expression to match the files
            // PERF NOTE: Constructing a Regex object is expensive, so we avoid it whenever possible
            bool matchWithRegex =
                // if we have a directory specification that uses wildcards, and
                (wildcardDirectoryPart.Length > 0) &&
                // the specification is not a simple "**"
                (wildcardDirectoryPart != (recursiveDirectoryMatch + s_directorySeparator));
            // then we need to use the regular expression

            // if we're not using the regular expression, get the file pattern extension
            string extensionPart = matchWithRegex
                ? null
                : Path.GetExtension(filenamePart);

            // check if the file pattern would cause Windows to match more loosely on the extension
            // NOTE: Windows matches loosely in two cases (in the absence of the * wildcard in the extension):
            // 1) if the extension ends with the ? wildcard, it matches files with shorter extensions also e.g. "file.tx?" would
            //    match both "file.txt" and "file.tx"
            // 2) if the extension is three characters, and the filename contains the * wildcard, it matches files with longer
            //    extensions that start with the same three characters e.g. "*.htm" would match both "file.htm" and "file.html"
            bool needToEnforceExtensionLength =
                    (extensionPart != null) &&
                    (extensionPart.IndexOf('*') == -1)
                &&
                    (extensionPart.EndsWith("?", StringComparison.Ordinal)
                ||
                    ((extensionPart.Length == (3 + 1 /* +1 for the period */)) &&
                    (filenamePart.IndexOf('*') != -1)));

            /*
             * Now get the files that match, starting at the lowest fixed directory.
             */
            try
            {
                GetFilesRecursive(listOfFiles, fixedDirectoryPart, wildcardDirectoryPart,
                    // if using the regular expression, ignore the file pattern
                    (matchWithRegex ? null : filenamePart), (needToEnforceExtensionLength ? extensionPart.Length : 0),
                    // if using the file pattern, ignore the regular expression
                    (matchWithRegex ? new Regex(matchFileExpression, RegexOptions.IgnoreCase) : null),
                    needsRecursion, projectDirectoryUnescaped, stripProjectDirectory, getFileSystemEntries);
            }
            catch (Exception ex) when (ExceptionHandling.IsIoRelatedException(ex))
            {
                // Assume it's not meant to be a path
                return new[] { filespecUnescaped };
            }

            /*
             * Build the return array.
             */
            string[] files = (string[])arrayListOfFiles.ToArray(typeof(string));
            return files;
        }
Example #22
0
 internal static void SplitFileSpec(string filespec, out string fixedDirectoryPart, out string wildcardDirectoryPart, out string filenamePart, GetFileSystemEntries getFileSystemEntries)
 {
     PreprocessFileSpecForSplitting(filespec, out fixedDirectoryPart, out wildcardDirectoryPart, out filenamePart);
     if ("**" == filenamePart)
     {
         wildcardDirectoryPart = wildcardDirectoryPart + "**";
         wildcardDirectoryPart = wildcardDirectoryPart + directorySeparator;
         filenamePart          = "*.*";
     }
     fixedDirectoryPart = GetLongPathName(fixedDirectoryPart, getFileSystemEntries);
 }
Example #23
0
        /// <summary>
        /// Given a pattern (filespec) and a candidate filename (fileToMatch)
        /// return matching information.
        /// </summary>
        /// <param name="filespec">The filespec.</param>
        /// <param name="fileToMatch">The candidate to match against.</param>
        /// <param name="getFileSystemEntries">Delegate.</param>
        /// <returns>The result class.</returns>
        internal static Result FileMatch
        (
            string filespec,
            string fileToMatch,
            GetFileSystemEntries getFileSystemEntries
        )
        {
            Result matchResult = new Result();

            fileToMatch = GetLongPathName(fileToMatch, getFileSystemEntries);

            Regex regexFileMatch;
            GetFileSpecInfo
            (
                filespec,
                out regexFileMatch,
                out matchResult.isFileSpecRecursive,
                out matchResult.isLegalFileSpec,
                getFileSystemEntries
            );

            if (matchResult.isLegalFileSpec)
            {
                Match match = regexFileMatch.Match(fileToMatch);
                matchResult.isMatch = match.Success;

                if (matchResult.isMatch)
                {
                    matchResult.fixedDirectoryPart = match.Groups["FIXEDDIR"].Value;
                    matchResult.wildcardDirectoryPart = match.Groups["WILDCARDDIR"].Value;
                    matchResult.filenamePart = match.Groups["FILENAME"].Value;
                }
            }

            return matchResult;
        }