File: FileSystem\DirectoryCacheFileSystemWrapper.cs
Web Access
Project: ..\..\..\src\Build\Microsoft.Build.csproj (Microsoft.Build)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
 
#if FEATURE_MSIOREDIST
using Path = Microsoft.IO.Path;
#endif
 
#nullable disable
 
namespace Microsoft.Build.FileSystem
{
    internal class DirectoryCacheFileSystemWrapper : IFileSystem
    {
        /// <summary>
        /// The base <see cref="IFileSystem"/> to fall back to for functionality not provided by <see cref="_directoryCache"/>.
        /// </summary>
        private readonly IFileSystem _fileSystem;
 
        /// <summary>
        /// A host-provided cache used for file existence and directory enumeration.
        /// </summary>
        private readonly IDirectoryCache _directoryCache;
 
        public DirectoryCacheFileSystemWrapper(IFileSystem fileSystem, IDirectoryCache directoryCache)
        {
            _fileSystem = fileSystem;
            _directoryCache = directoryCache;
        }
 
        #region IFileSystem implementation based on IDirectoryCache
 
        public bool FileOrDirectoryExists(string path)
        {
            return _directoryCache.FileExists(path) || _directoryCache.DirectoryExists(path);
        }
 
        public bool DirectoryExists(string path)
        {
            return _directoryCache.DirectoryExists(path);
        }
 
        public bool FileExists(string path)
        {
            return _directoryCache.FileExists(path);
        }
 
        public IEnumerable<string> EnumerateDirectories(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            if (searchOption != SearchOption.TopDirectoryOnly)
            {
                // Recursive enumeration is not used during evaluation, pass it through.
                return _fileSystem.EnumerateDirectories(path, searchPattern, searchOption);
            }
            return EnumerateFullFileSystemPaths(path, searchPattern, includeFiles: false, includeDirectories: true);
        }
 
        public IEnumerable<string> EnumerateFiles(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            if (searchOption != SearchOption.TopDirectoryOnly)
            {
                // Recursive enumeration is not used during evaluation, pass it through.
                return _fileSystem.EnumerateFiles(path, searchPattern, searchOption);
            }
            return EnumerateFullFileSystemPaths(path, searchPattern, includeFiles: true, includeDirectories: false);
        }
 
        public IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            if (searchOption != SearchOption.TopDirectoryOnly)
            {
                // Recursive enumeration is not used during evaluation, pass it through.
                return _fileSystem.EnumerateFileSystemEntries(path, searchPattern, searchOption);
            }
            return EnumerateFullFileSystemPaths(path, searchPattern, includeFiles: true, includeDirectories: true);
        }
 
        private IEnumerable<string> EnumerateFullFileSystemPaths(string path, string searchPattern, bool includeFiles, bool includeDirectories)
        {
            FindPredicate predicate = (ref ReadOnlySpan<char> fileName) =>
            {
                return FileMatcher.IsAllFilesWildcard(searchPattern) || FileMatcher.IsMatch(fileName, searchPattern);
            };
 
#if !FEATURE_MSIOREDIST && NETFRAMEWORK
            FindTransform<string> transform = (ref ReadOnlySpan<char> fileName) => Path.Combine(path, fileName.ToString());
#else
            FindTransform<string> transform = (ref ReadOnlySpan<char> fileName) => Path.Join(path.AsSpan(), fileName);
#endif
            IEnumerable<string> directories = includeDirectories
                ? _directoryCache.EnumerateDirectories(path, searchPattern, predicate, transform)
                : [];
            IEnumerable<string> files = includeFiles
                ? _directoryCache.EnumerateFiles(path, searchPattern, predicate, transform)
                : [];
 
            return Enumerable.Concat(directories, files);
        }
 
        #endregion
 
        #region IFileSystem pass-through implementation
 
        public FileAttributes GetAttributes(string path) => _fileSystem.GetAttributes(path);
 
        public DateTime GetLastWriteTimeUtc(string path) => _fileSystem.GetLastWriteTimeUtc(path);
 
        public TextReader ReadFile(string path) => _fileSystem.ReadFile(path);
 
        public Stream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share) => _fileSystem.GetFileStream(path, mode, access, share);
 
        public string ReadFileAllText(string path) => _fileSystem.ReadFileAllText(path);
 
        public byte[] ReadFileAllBytes(string path) => _fileSystem.ReadFileAllBytes(path);
 
        #endregion
    }
}