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;
}
}
}