private static IEnumerable<FilePatternMatch> GetIncludeFilesCore( string sourceBasePath, List<string> includePatterns, List<string> excludePatterns, List<string> includeFiles, List<string> builtInsInclude, List<string> builtInsExclude) { var literalIncludedFiles = new List<string>(); if (includeFiles != null) { // literal included files are added at the last, but the search happens early // so as to make the process fail early in case there is missing file. fail early // helps to avoid unnecessary globing for performance optimization foreach (var literalRelativePath in includeFiles) { var fullPath = Path.GetFullPath(Path.Combine(sourceBasePath, literalRelativePath)); if (!File.Exists(fullPath)) { throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath)); } literalIncludedFiles.Add(fullPath); } } // Globbing var matcher = new Matcher(); if (builtInsInclude != null) { matcher.AddIncludePatterns(builtInsInclude); } if (includePatterns != null) { matcher.AddIncludePatterns(includePatterns); } if (builtInsExclude != null) { matcher.AddExcludePatterns(builtInsExclude); } if (excludePatterns != null) { matcher.AddExcludePatterns(excludePatterns); } return matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(sourceBasePath))).Files; }
internal static IEnumerable<PhysicalPackageFile> CollectAdditionalFiles( DirectoryInfoBase rootDirectory, IEnumerable<PackIncludeEntry> projectFileGlobs, string projectFilePath, IList<DiagnosticMessage> diagnostics) { foreach (var entry in projectFileGlobs) { // Evaluate the globs on the right var matcher = new Matcher(); matcher.AddIncludePatterns(entry.SourceGlobs); var results = matcher.Execute(rootDirectory); var files = results.Files.ToList(); // Check for illegal characters if (string.IsNullOrEmpty(entry.Target)) { diagnostics.Add(new DiagnosticMessage( ErrorCodes.NU1003, $"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. The target '{entry.Target}' is invalid, " + "targets must either be a file name or a directory suffixed with '/'. " + "The root directory of the package can be specified by using a single '/' character.", projectFilePath, DiagnosticMessageSeverity.Error, entry.Line, entry.Column)); continue; } if (entry.Target.Split('/').Any(s => s.Equals(".") || s.Equals(".."))) { diagnostics.Add(new DiagnosticMessage( ErrorCodes.NU1004, $"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " + $"The target '{entry.Target}' contains path-traversal characters ('.' or '..'). " + "These characters are not permitted in target paths.", projectFilePath, DiagnosticMessageSeverity.Error, entry.Line, entry.Column)); continue; } // Check the arity of the left if (entry.Target.EndsWith("/")) { var dir = entry.Target.Substring(0, entry.Target.Length - 1).Replace('/', Path.DirectorySeparatorChar); foreach (var file in files) { yield return new PhysicalPackageFile() { SourcePath = Path.Combine(rootDirectory.FullName, PathUtility.GetPathWithDirectorySeparator(file.Path)), TargetPath = Path.Combine(dir, PathUtility.GetPathWithDirectorySeparator(file.Stem)) }; } } else { // It's a file. If the glob matched multiple things, we're sad :( if (files.Count > 1) { // Arity mismatch! string sourceValue = entry.SourceGlobs.Length == 1 ? $"\"{entry.SourceGlobs[0]}\"" : ("[" + string.Join(",", entry.SourceGlobs.Select(v => $"\"{v}\"")) + "]"); diagnostics.Add(new DiagnosticMessage( ErrorCodes.NU1005, $"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " + $"The target '{entry.Target}' refers to a single file, but the pattern {sourceValue} " + "produces multiple files. To mark the target as a directory, suffix it with '/'.", projectFilePath, DiagnosticMessageSeverity.Error, entry.Line, entry.Column)); } else { yield return new PhysicalPackageFile() { SourcePath = Path.Combine(rootDirectory.FullName, files[0].Path), TargetPath = PathUtility.GetPathWithDirectorySeparator(entry.Target) }; } } } }