/// <summary> /// Used for the purposes of evaluating an item specification. Given a filespec that may include wildcard characters * and /// ?, we translate it into an actual list of files. If the input filespec doesn't contain any wildcard characters, and it /// doesn't appear to point to an actual file on disk, then we just give back the input string as an array of length one, /// assuming that it wasn't really intended to be a filename (as items are not required to necessarily represent files). /// Any wildcards passed in that are unescaped will be treated as real wildcards. /// The "include" of items passed back from the filesystem will be returned canonically escaped. /// The ordering of the list returned is deterministic (it is sorted). /// Will never throw IO exceptions: if there is no match, returns the input verbatim. /// </summary> /// <param name="directoryEscaped">The directory to evaluate, escaped.</param> /// <param name="filespecEscaped">The filespec to evaluate, escaped.</param> /// <param name="returnEscaped"><code>true</code> to return escaped specs.</param> /// <param name="excludeSpecsEscaped">The exclude specification, escaped.</param> /// <returns>Array of file paths.</returns> private static string[] GetFileList ( string directoryEscaped, string filespecEscaped, bool returnEscaped, IEnumerable <string> excludeSpecsEscaped = null ) { ErrorUtilities.VerifyThrowInternalLength(filespecEscaped, "filespecEscaped"); if (excludeSpecsEscaped == null) { excludeSpecsEscaped = Enumerable.Empty <string>(); } string[] fileList; if (FilespecHasWildcards(filespecEscaped)) { // Unescape before handing it to the filesystem. var directoryUnescaped = EscapingUtilities.UnescapeAll(directoryEscaped); var filespecUnescaped = EscapingUtilities.UnescapeAll(filespecEscaped); var excludeSpecsUnescaped = excludeSpecsEscaped.Where(IsValidExclude).Select(EscapingUtilities.UnescapeAll).ToList(); // Get the list of actual files which match the filespec. Put // the list into a string array. If the filespec started out // as a relative path, we will get back a bunch of relative paths. // If the filespec started out as an absolute path, we will get // back a bunch of absolute paths. fileList = FileMatcher.GetFiles(directoryUnescaped, filespecUnescaped, excludeSpecsUnescaped); ErrorUtilities.VerifyThrow(fileList != null, "We must have a list of files here, even if it's empty."); // Before actually returning the file list, we sort them alphabetically. This // provides a certain amount of extra determinism and reproducability. That is, // we're sure that the build will behave in exactly the same way every time, // and on every machine. Array.Sort(fileList, StringComparer.OrdinalIgnoreCase); if (returnEscaped) { // We must now go back and make sure all special characters are escaped because we always // store data in the engine in escaped form so it doesn't interfere with our parsing. // Note that this means that characters that were not escaped in the original filespec // may now be escaped, but that's not easy to avoid. for (int i = 0; i < fileList.Length; i++) { fileList[i] = EscapingUtilities.Escape(fileList[i]); } } } else { // Just return the original string. fileList = new string[] { returnEscaped?filespecEscaped : EscapingUtilities.UnescapeAll(filespecEscaped) }; } return(fileList); }
/// <summary> /// Expand wildcards in the item list. /// </summary> /// <param name="expand"></param> /// <returns>Array of items expanded</returns> public static ITaskItem[] ExpandWildcards(ITaskItem[] expand) { if (expand == null) { return(null); } else { List <ITaskItem> expanded = new List <ITaskItem>(expand.Length); foreach (ITaskItem i in expand) { if (FileMatcher.HasWildcards(i.ItemSpec)) { string[] files; string directoryName = Path.GetDirectoryName(i.ItemSpec); string searchPattern = Path.GetFileName(i.ItemSpec); // Very often with TLog files we're talking about // a directory and a simply wildcarded filename // Optimize for that case here. if (!FileMatcher.HasWildcards(directoryName) && Directory.Exists(directoryName)) { files = Directory.GetFiles(directoryName, searchPattern); } else { files = FileMatcher.GetFiles(null, i.ItemSpec); } foreach (string file in files) { TaskItem newItem = new TaskItem((ITaskItem)i); newItem.ItemSpec = file; expanded.Add(newItem); } } else { expanded.Add(i); } } return(expanded.ToArray()); } }
/// <summary> /// Expand wildcards in the item list. /// </summary> /// <param name="expand"></param> /// <returns></returns> private static ITaskItem[] ExpandWildcards(ITaskItem[] expand) { if (expand == null) { return(null); } else { ArrayList expanded = new ArrayList(); foreach (ITaskItem i in expand) { if (FileMatcher.HasWildcards(i.ItemSpec)) { string[] files = FileMatcher.GetFiles(null /* use current directory */, i.ItemSpec); foreach (string file in files) { TaskItem newItem = new TaskItem((ITaskItem)i); newItem.ItemSpec = file; // Compute the RecursiveDir portion. FileMatcher.Result match = FileMatcher.FileMatch(i.ItemSpec, file); if (match.isLegalFileSpec && match.isMatch) { if (match.wildcardDirectoryPart != null && match.wildcardDirectoryPart.Length > 0) { newItem.SetMetadata(FileUtilities.ItemSpecModifiers.RecursiveDir, match.wildcardDirectoryPart); } } expanded.Add(newItem); } } else { expanded.Add(i); } } return((ITaskItem[])expanded.ToArray(typeof(ITaskItem))); } }
public static ITaskItem[] ExpandWildcards(ITaskItem[] expand) { if (expand == null) { return(null); } List <ITaskItem> list = new List <ITaskItem>(expand.Length); foreach (ITaskItem item in expand) { if (FileMatcher.HasWildcards(item.ItemSpec)) { string[] files; string directoryName = Path.GetDirectoryName(item.ItemSpec); string fileName = Path.GetFileName(item.ItemSpec); if (!FileMatcher.HasWildcards(directoryName) && Directory.Exists(directoryName)) { files = Directory.GetFiles(directoryName, fileName); } else { files = FileMatcher.GetFiles(null, item.ItemSpec); } foreach (string str3 in files) { TaskItem item2 = new TaskItem(item) { ItemSpec = str3 }; list.Add(item2); } } else { list.Add(item); } } return(list.ToArray()); }
private static string[] GetFileList ( string directoryEscaped, string filespecEscaped, bool returnEscaped, bool forceEvaluateWildCards, IEnumerable <string> excludeSpecsEscaped, FileMatcher fileMatcher, object loggingMechanism = null, IElementLocation includeLocation = null, IElementLocation excludeLocation = null, IElementLocation importLocation = null, BuildEventContext buildEventContext = null, string buildEventFileInfoFullPath = null, bool disableExcludeDriveEnumerationWarning = false ) { ErrorUtilities.VerifyThrowInternalLength(filespecEscaped, nameof(filespecEscaped)); string[] fileList; // Used to properly detect and log drive enumerating wildcards when applicable. FileMatcher.SearchAction action = FileMatcher.SearchAction.None; string excludeFileSpec = string.Empty; if (!FilespecHasWildcards(filespecEscaped) || FilespecMatchesLazyWildcard(filespecEscaped, forceEvaluateWildCards)) { // Just return the original string. fileList = new string[] { returnEscaped?filespecEscaped : EscapingUtilities.UnescapeAll(filespecEscaped) }; } else { if (Traits.Instance.LogExpandedWildcards) { ErrorUtilities.DebugTraceMessage("Expanding wildcard for file spec {0}", filespecEscaped); } // Unescape before handing it to the filesystem. var directoryUnescaped = EscapingUtilities.UnescapeAll(directoryEscaped); var filespecUnescaped = EscapingUtilities.UnescapeAll(filespecEscaped); var excludeSpecsUnescaped = excludeSpecsEscaped?.Where(IsValidExclude).Select(i => EscapingUtilities.UnescapeAll(i)).ToList(); // Get the list of actual files which match the filespec. Put // the list into a string array. If the filespec started out // as a relative path, we will get back a bunch of relative paths. // If the filespec started out as an absolute path, we will get // back a bunch of absolute paths. Also retrieves the search action // and relevant Exclude filespec for drive enumerating wildcard detection. (fileList, action, excludeFileSpec) = fileMatcher.GetFiles(directoryUnescaped, filespecUnescaped, excludeSpecsUnescaped); // Determines whether Exclude filespec or passed in file spec should be // used in drive enumeration warning or exception. bool excludeFileSpecIsEmpty = string.IsNullOrWhiteSpace(excludeFileSpec); string fileSpec = excludeFileSpecIsEmpty ? filespecUnescaped : excludeFileSpec; switch (action) { case (FileMatcher.SearchAction.LogDriveEnumeratingWildcard): switch (loggingMechanism) { // Logging mechanism received from ItemGroupIntrinsicTask. case TargetLoggingContext targetLoggingContext: LogDriveEnumerationWarningWithTargetLoggingContext( targetLoggingContext, includeLocation, excludeFileSpecIsEmpty, disableExcludeDriveEnumerationWarning, fileSpec); break; // Logging mechanism received from Evaluator. case ILoggingService loggingService: LogDriveEnumerationWarningWithLoggingService( loggingService, buildEventContext, buildEventFileInfoFullPath, filespecUnescaped); break; // Logging mechanism received from Evaluator and LazyItemEvaluator.IncludeOperation. case EvaluationLoggingContext evaluationLoggingContext: LogDriveEnumerationWarningWithEvaluationLoggingContext( evaluationLoggingContext, importLocation, excludeFileSpecIsEmpty, filespecUnescaped, fileSpec); break; default: throw new InternalErrorException($"Logging type {loggingMechanism.GetType()} is not understood by {nameof(GetFileList)}."); } break; case (FileMatcher.SearchAction.FailOnDriveEnumeratingWildcard): switch (loggingMechanism) { // Logging mechanism received from ItemGroupIntrinsicTask. case TargetLoggingContext targetLoggingContext: ThrowDriveEnumerationExceptionWithTargetLoggingContext( includeLocation, excludeLocation, excludeFileSpecIsEmpty, filespecUnescaped, fileSpec); break; // Logging mechanism received from Evaluator. case ILoggingService loggingService: ThrowDriveEnumerationExceptionWithLoggingService(includeLocation, filespecUnescaped); break; // Logging mechanism received from Evaluator and LazyItemEvaluator.IncludeOperation. case EvaluationLoggingContext evaluationLoggingContext: ThrowDriveEnumerationExceptionWithEvaluationLoggingContext( importLocation, includeLocation, excludeLocation, filespecUnescaped, fileSpec, excludeFileSpecIsEmpty); break; default: throw new InternalErrorException($"Logging type {loggingMechanism.GetType()} is not understood by {nameof(GetFileList)}."); } break; default: break; } ErrorUtilities.VerifyThrow(fileList != null, "We must have a list of files here, even if it's empty."); // Before actually returning the file list, we sort them alphabetically. This // provides a certain amount of extra determinism and reproducability. That is, // we're sure that the build will behave in exactly the same way every time, // and on every machine. Array.Sort(fileList, StringComparer.OrdinalIgnoreCase); if (returnEscaped) { // We must now go back and make sure all special characters are escaped because we always // store data in the engine in escaped form so it doesn't interfere with our parsing. // Note that this means that characters that were not escaped in the original filespec // may now be escaped, but that's not easy to avoid. for (int i = 0; i < fileList.Length; i++) { fileList[i] = EscapingUtilities.Escape(fileList[i]); } } } return(fileList); }
/// <summary> /// Used for the purposes of evaluating an item specification. Given a filespec that may include wildcard characters * and /// ?, we translate it into an actual list of files. If the input filespec doesn't contain any wildcard characters, and it /// doesn't appear to point to an actual file on disk, then we just give back the input string as an array of length one, /// assuming that it wasn't really intended to be a filename (as items are not required to necessarily represent files). /// </summary> /// <owner>RGoel</owner> /// <param name="filespec">The filespec to evaluate.</param> /// <returns>Array of file paths.</returns> internal static string[] GetFileListEscaped ( string directory, string filespec ) { ErrorUtilities.VerifyThrow(filespec.Length > 0, "Need a valid file-spec."); string[] fileList; bool containsEscapedWildcards = EscapingUtilities.ContainsEscapedWildcards(filespec); bool containsRealWildcards = FileMatcher.HasWildcards(filespec); if (containsEscapedWildcards && containsRealWildcards) { // Umm, this makes no sense. The item's Include has both escaped wildcards and // real wildcards. What does he want us to do? Go to the file system and find // files that literally have '*' in their filename? Well, that's not going to // happen because '*' is an illegal character to have in a filename. // Just return the original string. fileList = new string[] { EscapingUtilities.Escape(filespec) }; } else if (!containsEscapedWildcards && containsRealWildcards) { // Unescape before handing it to the filesystem. string filespecUnescaped = EscapingUtilities.UnescapeAll(filespec); // Get the list of actual files which match the filespec. Put // the list into a string array. If the filespec started out // as a relative path, we will get back a bunch of relative paths. // If the filespec started out as an absolute path, we will get // back a bunch of absolute paths. fileList = FileMatcher.GetFiles(directory, filespecUnescaped); ErrorUtilities.VerifyThrow(fileList != null, "We must have a list of files here, even if it's empty."); // Before actually returning the file list, we sort them alphabetically. This // provides a certain amount of extra determinism and reproducability. That is, // we're sure that the build will behave in exactly the same way every time, // and on every machine. Array.Sort(fileList); // We must now go back and make sure all special characters are escaped because we always // store data in the engine in escaped form so it doesn't screw up our parsing. // Note that this means that characters that were not escaped in the original filespec // may now be escaped, but that's not easy to avoid. for (int i = 0; i < fileList.Length; i++) { fileList[i] = EscapingUtilities.Escape(fileList[i]); } } else { // No real wildcards means we just return the original string. Don't even bother // escaping ... it should already be escaped appropriately since it came directly // from the project file or the OM host. fileList = new string[] { filespec }; } return(fileList); }