using System; using System.IO; using System.Linq; namespace MfGames.IO.Extensions { /// /// Useful extension methods for DirectoryInfo. /// public static class DirectoryInfoExtensions { /// /// Makes sure a directory exists, creating it and any parents above it /// as needed. /// /// /// The directory passed in. public static DirectoryInfo? CreateIfMissing( this DirectoryInfo? directory) { // Ignore blanks. if (directory == null) { return null; } // Check the parent first. We don't have to worry about null because // we check that coming in. directory.Parent.CreateIfMissing(); // If the directory doesn't exist, create it. if (!Directory.Exists(directory.FullName)) { directory.Create(); } return directory; } /// /// Searches for the Git root starting at the given directory. /// /// The directory to start searching. /// The directory containing `.git`, otherwise null. public static DirectoryInfo? FindGitRoot(this DirectoryInfo? directory) { return directory.FindSelfOrParent(IsGitRoot); } /// /// Searches for a parent that matches the given `match` method. This /// will not compare the given directory to see if it matches. /// /// The directory to start searching. /// The function that takes a directory to determine a match. /// A parent directory that matches, otherwise null. public static DirectoryInfo? FindParent( this DirectoryInfo? directory, Func match) { return directory == null ? null : FindSelfOrParent(directory.Parent, match); } /// /// Searches the given directory and parents for the first one that /// matches (moving up the directory tree). If this does not find /// anything, then a null will be returned. /// /// The directory to start searching. /// The function that takes a directory to determine a match. /// A parent directory that matches, otherwise null. public static DirectoryInfo? FindSelfOrParent( this DirectoryInfo? directory, Func match) { while (true) { // Validate our inputs. if (match == null) { throw new ArgumentNullException(nameof(match)); } // If the directory is null, just return null. Same with // non-existing directories. We don't use directory.Exists here // because it seems to be cached and we get incorrect data. if (directory == null || !Directory.Exists(directory.FullName)) { return null; } // Check this directory for a match, otherwise move up. if (match(directory)) { return directory; } directory = directory.Parent; } } /// /// Gets a DirectoryInfo by combining the path components with the /// directory full path. /// /// The directory to get the root path. /// Additional child paths. /// A DirectoryInfo of the given path. public static DirectoryInfo GetDirectory( this DirectoryInfo directory, params string[] paths) { if (directory == null) { throw new ArgumentNullException(nameof(directory)); } if (paths == null) { throw new ArgumentNullException(nameof(paths)); } string[] parts = new[] { directory.FullName } .Union(paths) .ToArray(); string path = Path.Combine(parts); var info = new DirectoryInfo(path); return info; } /// /// Gets a FileInfo by combining the path components with the directory /// full path. /// /// The directory to get the root path. /// Additional child paths. /// A FileInfo of the given path. public static FileInfo GetFile( this DirectoryInfo directory, params string[] paths) { if (directory == null) { throw new ArgumentNullException(nameof(directory)); } if (paths == null) { throw new ArgumentNullException(nameof(paths)); } string[] parts = new[] { directory.FullName } .Union(paths) .ToArray(); string path = Path.Combine(parts); var info = new FileInfo(path); return info; } /// /// Determines if the given directory contains a ".git" folder. If given /// a null, this will always return false. /// /// The directory to inspect. /// True if the directory contains ".git", otherwise false. public static bool IsGitRoot(this DirectoryInfo? directory) { return directory != null && directory.GetDirectories(".git").Length > 0; } } }