Skip to content

Instantly share code, notes, and snippets.

@Dkowald
Last active January 3, 2019 05:22
Show Gist options
  • Select an option

  • Save Dkowald/efed4a9cddb86f6cf2de49b9166a4163 to your computer and use it in GitHub Desktop.

Select an option

Save Dkowald/efed4a9cddb86f6cf2de49b9166a4163 to your computer and use it in GitHub Desktop.
Resolve case-aware path.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
// ReSharper disable once CheckNamespace
namespace kwd.gist
{
/// <summary>
/// Utility to resolve file system path with case.
/// </summary>
public static class CaseAwarePath
{
/// <summary>
/// Resolve a Root(ed) path to match file-system case.
/// </summary>
/// <remarks>
/// To improve performance, resolve the root once; subsequent
/// resolution then limited to a specified sub-path.
/// </remarks>
public static DirectoryInfo Root(string root)
{
if (!Path.IsPathRooted(root))
{
throw new ArgumentException("The path must be absolute.", nameof(root));
}
var pathRoot = Path.GetPathRoot(root);
var foundPath = Resolve(new DirectoryInfo(pathRoot), root.Substring(pathRoot.Length));
return new DirectoryInfo(foundPath);
}
/// <summary>
/// Resolve case-aware sub-path; does NOT resolve root.
/// </summary>
/// <param name="root">Root directory, not included in the resolve</param>
/// <param name="subPath">A set of sub-path(s) to resolve</param>
public static string Resolve(DirectoryInfo root, params string[] subPath)
{
if (!root.Exists)
{
return Path.Combine(root.FullName, Path.Combine(subPath));
}
var segments = new Queue<string>(subPath);
var cur = root.FullName;
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;
}
/// <summary>
/// Resolve case-aware sub-path; does NOT resolve root.
/// </summary>
/// <param name="root">Root directory, not included in the resolve</param>
/// <param name="subPath">A sub-path string</param>
/// <returns>The full path with case matching any sub-path found on file-system</returns>
public static string Resolve(DirectoryInfo root, string subPath) => Resolve(root,
subPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.Where(x => !string.IsNullOrEmpty(x))
.ToArray());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment