Last active
January 3, 2019 05:32
-
-
Save Dkowald/859715d703f5c1030c679aa394c48679 to your computer and use it in GitHub Desktop.
Case aware FileProvider
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using Microsoft.Extensions.FileProviders; | |
using Microsoft.Extensions.Primitives; | |
// ReSharper disable once CheckNamespace | |
namespace kwd.gist | |
{ | |
/// <summary> | |
/// Resolves file system paths using case-aware path. | |
/// </summary> | |
public class CaseAwareFileProvider : IFileProvider, IDisposable | |
{ | |
private readonly PhysicalFileProvider _provider; | |
/// <summary> | |
/// Create case-aware file system provider. | |
/// </summary> | |
/// <remarks> | |
/// Uses a <see cref="PhysicalFileProvider"/> internally. | |
/// </remarks> | |
public CaseAwareFileProvider(string root) | |
{ | |
if (!Path.IsPathRooted(root)) | |
{ | |
throw new ArgumentException("The path must be absolute.", nameof(root)); | |
} | |
var pathRoot = Path.GetPathRoot(root); | |
var matchCase = ResolvePath(pathRoot, root.Substring(pathRoot.Length)); | |
_provider = new PhysicalFileProvider(matchCase); | |
} | |
/// <summary> | |
/// Root directory for this instance. | |
/// </summary> | |
public string Root => _provider.Root; | |
/// <summary> | |
/// Get file info for the specified sub path. | |
/// </summary> | |
public IFileInfo GetFileInfo(string subpath) | |
{ | |
var matchCase = ResolvePath(_provider.Root, subpath) | |
.Substring(_provider.Root.Length); | |
return _provider.GetFileInfo(matchCase); | |
} | |
/// <summary> | |
/// List of directory contents for the given sub path. | |
/// </summary> | |
public IDirectoryContents GetDirectoryContents(string subpath) | |
{ | |
var matchCase = ResolvePath(_provider.Root, subpath) | |
.Substring(_provider.Root.Length); | |
return _provider.GetDirectoryContents(matchCase); | |
} | |
/// <summary> | |
/// Watch changes to files (see <see cref="PhysicalFileProvider.Watch"/>). | |
/// </summary> | |
public IChangeToken Watch(string filter) => | |
_provider.Watch(filter); | |
/// <summary> | |
/// Release resources (see <see cref="PhysicalFileProvider.Dispose"/>). | |
/// </summary> | |
public void Dispose() => _provider.Dispose(); | |
private static string ResolvePath(string root, params string[] subPath) | |
{ | |
root = root ?? string.Empty; | |
if (root != string.Empty && !Directory.Exists(root)) | |
{ | |
return Path.Combine(root, Path.Combine(subPath)); | |
} | |
var pathSegments = subPath | |
.SelectMany(x => x.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) | |
.Where(x => !string.IsNullOrEmpty(x)) | |
.ToArray(); | |
var segments = new Queue<string>(pathSegments); | |
var cur = root; | |
while (segments.Any()) | |
{ | |
var next = segments.Dequeue(); | |
var part = Path.GetFileName(Directory.GetFileSystemEntries(cur, next).FirstOrDefault()); | |
if (part != null) | |
{ | |
cur = Path.Combine(cur, part); | |
} | |
else | |
{ | |
cur = Path.Combine(new[] | |
{cur, next}.Concat(segments).ToArray()); | |
break; | |
} | |
} | |
return cur; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment