Skip to content

Instantly share code, notes, and snippets.

@Dkowald
Last active January 3, 2019 05:32
Show Gist options
  • Save Dkowald/859715d703f5c1030c679aa394c48679 to your computer and use it in GitHub Desktop.
Save Dkowald/859715d703f5c1030c679aa394c48679 to your computer and use it in GitHub Desktop.
Case aware FileProvider
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