public IDirectoryContents GetDirectoryContents(string subpath) { var contents = new List <IFileInfo>(); var subPathParts = subpath.Split(ForwardSlashChar); // Remove the root identifier from the relative path if (string.Equals(subPathParts.FirstOrDefault(), RootDir, StringComparison.Ordinal)) { subPathParts = subPathParts.Skip(1).ToArray(); } foreach (var file in _files) { var i = 0; // Walk the path as long as both the file and subpath contain the same directories while (i < file.Length - 1 && i < subPathParts.Length && string.Equals(file[i], subPathParts[i], StringComparison.OrdinalIgnoreCase)) { i++; } // Check if the entire subpath was matched if (i == subPathParts.Length) { // All items are files. The last string in the array will be the file name. if (i == file.Length - 1) { // File var virtualFile = new VirtualFileInfo(string.Join(ForwardSlash, file)); contents.Add(virtualFile); } else { // Dir var dirPath = string.Join(ForwardSlash, file.Take(i + 1)); var virtualDir = new VirtualFileInfo(dirPath, isDirectory: true); contents.Add(virtualDir); } } } return(new EnumerableDirectoryContents(contents)); }
/// <summary> /// Apply build actions from the nuspec to items from the contentFiles folder. /// </summary> internal static List <LockFileContentFile> GetContentFileGroup( NuspecReader nuspec, List <ContentItemGroup> contentFileGroups) { var results = new List <LockFileContentFile>(contentFileGroups.Count); var rootFolderPathLength = ContentFilesFolderName.Length; // Read the contentFiles section of the nuspec // Read the entries so that the bottom entry has priority var nuspecContentFiles = nuspec.GetContentFiles().ToList(); // Initialize mappings var entryMappings = new Dictionary <string, List <ContentFilesEntry> >(StringComparer.OrdinalIgnoreCase); var languageMappings = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var group in contentFileGroups) { var codeLanguage = group.Properties[ManagedCodeConventions.PropertyNames.CodeLanguage] as string; foreach (var item in group.Items) { if (!entryMappings.ContainsKey(item.Path)) { entryMappings.Add(item.Path, new List <ContentFilesEntry>()); languageMappings.Add(item.Path, codeLanguage); } } } // Virtual root for file globbing var rootDirectory = new VirtualFileInfo(VirtualFileProvider.RootDir, isDirectory: true); // Apply all nuspec property mappings to the files returned by content model foreach (var filesEntry in nuspecContentFiles) { // this is validated in the nuspec reader Debug.Assert(filesEntry.Include != null, "invalid contentFiles entry"); // Create a filesystem matcher for globbing patterns var matcher = new Matcher(StringComparison.OrdinalIgnoreCase); matcher.AddInclude(filesEntry.Include); if (filesEntry.Exclude != null) { matcher.AddExclude(filesEntry.Exclude); } // Check each file against the patterns foreach (var file in entryMappings.Keys) { // Remove contentFiles/ from the string Debug.Assert(file.StartsWith(ContentFilesFolderName, StringComparison.OrdinalIgnoreCase), "invalid file path: " + file); // All files should begin with the same root folder if (file.Length > rootFolderPathLength) { var relativePath = file.Substring(rootFolderPathLength, file.Length - rootFolderPathLength); // Check if the nuspec group include/exclude patterns apply to the file var virtualDirectory = new VirtualFileProvider(new List <string>() { relativePath }); var globbingDirectory = new FileProviderGlobbingDirectory( virtualDirectory, fileInfo: rootDirectory, parent: null); // Currently Matcher only returns the file name not the full path, each file must be // check individually. var matchResults = matcher.Execute(globbingDirectory); if (matchResults.Files.Any()) { entryMappings[file].Add(filesEntry); } } } } // Create lock file entries for each item in the contentFiles folder foreach (var file in entryMappings.Keys) { // defaults var action = BuildAction.Parse(PackagingConstants.ContentFilesDefaultBuildAction); var copyToOutput = false; var flatten = false; // _._ is needed for empty codeLanguage groups if (file.EndsWith(PackagingCoreConstants.ForwardSlashEmptyFolder, StringComparison.Ordinal)) { action = BuildAction.None; } else { // apply each entry // entries may not have all the attributes, if a value is null // ignore it and continue using the previous value. foreach (var filesEntry in entryMappings[file]) { if (!string.IsNullOrEmpty(filesEntry.BuildAction)) { action = BuildAction.Parse(filesEntry.BuildAction); } if (filesEntry.CopyToOutput.HasValue) { copyToOutput = filesEntry.CopyToOutput.Value; } if (filesEntry.Flatten.HasValue) { flatten = filesEntry.Flatten.Value; } } } // Add attributes to the lock file item var lockFileItem = new LockFileContentFile(file); // Add the language from the directory path lockFileItem.CodeLanguage = languageMappings[file].ToLowerInvariant(); if (!action.IsKnown) { // Throw an error containing the package identity, invalid action, and file where it occurred. var message = string.Format(CultureInfo.CurrentCulture, Strings.Error_UnknownBuildAction, nuspec.GetIdentity(), action, file); throw new PackagingException(message); } lockFileItem.BuildAction = action; lockFileItem.CopyToOutput = copyToOutput; // Check if this is a .pp transform. If the filename is ".pp" ignore it since it will // have no file name after the transform. var isPP = lockFileItem.Path.EndsWith(".pp", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Path.GetFileNameWithoutExtension(lockFileItem.Path)); if (copyToOutput) { string destination = null; if (flatten) { destination = Path.GetFileName(lockFileItem.Path); } else { // Find path relative to the TxM // Ex: contentFiles/cs/net45/config/config.xml -> config/config.xml destination = GetContentFileFolderRelativeToFramework(file); } if (isPP) { // Remove .pp from the output file path destination = destination.Substring(0, destination.Length - 3); } lockFileItem.OutputPath = destination; } // Add the pp transform file if one exists if (isPP) { var destination = lockFileItem.Path.Substring(0, lockFileItem.Path.Length - 3); destination = GetContentFileFolderRelativeToFramework(destination); lockFileItem.PPOutputPath = destination; } results.Add(lockFileItem); } return(results); }