Files
SabreTools/SabreTools.Library/IO/DirectoryExtensions.cs

342 lines
14 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SabreTools.Library.Logging;
using NaturalSort;
2020-08-01 23:04:11 -07:00
namespace SabreTools.Library.IO
{
/// <summary>
/// Extensions to Directory functionality
/// </summary>
public static class DirectoryExtensions
{
/// <summary>
/// Cleans out the temporary directory
/// </summary>
/// <param name="dir">Name of the directory to clean out</param>
public static void Clean(string dir)
{
foreach (string file in Directory.EnumerateFiles(dir, "*", SearchOption.TopDirectoryOnly))
{
FileExtensions.TryDelete(file);
}
foreach (string subdir in Directory.EnumerateDirectories(dir, "*", SearchOption.TopDirectoryOnly))
{
TryDelete(subdir);
}
}
/// <summary>
/// Ensure the output directory is a proper format and can be created
/// </summary>
/// <param name="dir">Directory to check</param>
/// <param name="create">True if the directory should be created, false otherwise (default)</param>
/// <param name="temp">True if this is a temp directory, false otherwise</param>
/// <returns>Full path to the directory</returns>
public static string Ensure(string dir, bool create = false, bool temp = false)
{
// If the output directory is invalid
if (string.IsNullOrWhiteSpace(dir))
{
if (temp)
dir = Path.GetTempPath();
else
dir = Environment.CurrentDirectory;
}
// Get the full path for the output directory
dir = Path.GetFullPath(dir);
// If we're creating the output folder, do so
if (create)
Directory.CreateDirectory(dir);
return dir;
}
/// <summary>
/// Retrieve a list of just directories from inputs
/// </summary>
/// <param name="inputs">List of strings representing directories and files</param>
2020-07-26 23:39:33 -07:00
/// <param name="appendparent">True if the parent name should be included in the ParentablePath, false otherwise (default)</param>
/// <returns>List of strings representing just directories from the inputs</returns>
2020-07-26 23:39:33 -07:00
public static List<ParentablePath> GetDirectoriesOnly(List<string> inputs, bool appendparent = false)
{
2020-07-26 23:39:33 -07:00
List<ParentablePath> outputs = new List<ParentablePath>();
2020-08-08 21:53:34 -07:00
for (int i = 0; i < inputs.Count; i++)
{
2020-08-08 21:53:34 -07:00
string input = inputs[i];
2020-08-17 14:10:53 -07:00
// If we have a null or empty path
if (string.IsNullOrEmpty(input))
continue;
2020-08-08 21:53:34 -07:00
// If we have a wildcard
string pattern = "*";
if (input.Contains("*") || input.Contains("?"))
{
pattern = Path.GetFileName(input);
input = input.Substring(0, input.Length - pattern.Length);
}
2020-08-17 14:10:53 -07:00
// Get the parent path in case of appending
string parentPath;
try
{
2020-08-17 14:10:53 -07:00
parentPath = Path.GetFullPath(input);
}
catch (Exception ex)
{
LoggerImpl.Error(ex, $"An exception occurred getting the full path for '{input}'");
2020-08-17 14:10:53 -07:00
continue;
}
2020-07-26 23:39:33 -07:00
2020-08-17 14:10:53 -07:00
if (Directory.Exists(input))
{
2020-08-08 21:53:34 -07:00
List<string> directories = GetDirectoriesOrdered(input, pattern);
foreach (string dir in directories)
{
try
{
2020-07-26 23:39:33 -07:00
outputs.Add(new ParentablePath(Path.GetFullPath(dir), appendparent ? parentPath : string.Empty));
}
2020-09-15 12:12:13 -07:00
catch (PathTooLongException ex)
{
LoggerImpl.Warning(ex, $"The path for '{dir}' was too long");
}
catch (Exception ex)
{
LoggerImpl.Error(ex, $"An exception occurred processing '{dir}'");
}
}
}
}
return outputs;
}
/// <summary>
/// Retrieve a list of directories from a directory recursively in proper order
/// </summary>
/// <param name="dir">Directory to parse</param>
2020-08-08 21:53:34 -07:00
/// <param name="pattern">Optional pattern to search for directory names</param>
/// <returns>List with all new files</returns>
2020-08-08 21:53:34 -07:00
private static List<string> GetDirectoriesOrdered(string dir, string pattern = "*")
{
2020-08-08 21:53:34 -07:00
return GetDirectoriesOrderedHelper(dir, new List<string>(), pattern);
}
/// <summary>
/// Retrieve a list of directories from a directory recursively in proper order
/// </summary>
/// <param name="dir">Directory to parse</param>
/// <param name="infiles">List representing existing files</param>
2020-08-08 21:53:34 -07:00
/// <param name="pattern">Optional pattern to search for directory names</param>
/// <returns>List with all new files</returns>
2020-08-08 21:53:34 -07:00
private static List<string> GetDirectoriesOrderedHelper(string dir, List<string> infiles, string pattern)
{
// Take care of the files in the top directory
2020-08-08 21:53:34 -07:00
List<string> toadd = Directory.EnumerateDirectories(dir, pattern, SearchOption.TopDirectoryOnly).ToList();
toadd.Sort(new NaturalComparer());
infiles.AddRange(toadd);
// Then recurse through and add from the directories
foreach (string subDir in toadd)
{
2020-08-08 21:53:34 -07:00
infiles = GetDirectoriesOrderedHelper(subDir, infiles, pattern);
}
// Return the new list
return infiles;
}
/// <summary>
/// Retrieve a list of just files from inputs
/// </summary>
/// <param name="inputs">List of strings representing directories and files</param>
2020-07-26 23:39:33 -07:00
/// <param name="appendparent">True if the parent name should be be included in the ParentablePath, false otherwise (default)</param>
/// <returns>List of strings representing just files from the inputs</returns>
2020-07-26 23:39:33 -07:00
public static List<ParentablePath> GetFilesOnly(List<string> inputs, bool appendparent = false)
{
2020-07-26 23:39:33 -07:00
List<ParentablePath> outputs = new List<ParentablePath>();
2020-08-08 21:53:34 -07:00
for (int i = 0; i < inputs.Count; i++)
{
string input = inputs[i].Trim('"');
2020-08-08 21:53:34 -07:00
2020-08-17 14:10:53 -07:00
// If we have a null or empty path
if (string.IsNullOrEmpty(input))
continue;
2020-08-08 21:53:34 -07:00
// If we have a wildcard
string pattern = "*";
if (input.Contains("*") || input.Contains("?"))
{
pattern = Path.GetFileName(input);
input = input.Substring(0, input.Length - pattern.Length);
}
2020-07-26 23:39:33 -07:00
// Get the parent path in case of appending
2020-08-17 13:48:05 -07:00
string parentPath;
try
{
parentPath = Path.GetFullPath(input);
}
catch (Exception ex)
{
LoggerImpl.Error(ex, $"An exception occurred getting the full path for '{input}'");
2020-08-17 13:48:05 -07:00
continue;
}
2020-07-26 23:39:33 -07:00
if (Directory.Exists(input))
{
2020-08-08 21:53:34 -07:00
List<string> files = GetFilesOrdered(input, pattern);
foreach (string file in files)
{
try
{
2020-07-26 23:39:33 -07:00
outputs.Add(new ParentablePath(Path.GetFullPath(file), appendparent ? parentPath : string.Empty));
}
2020-09-15 12:12:13 -07:00
catch (PathTooLongException ex)
{
LoggerImpl.Warning(ex, $"The path for '{file}' was too long");
}
catch (Exception ex)
{
LoggerImpl.Error(ex, $"An exception occurred processing '{file}'");
}
}
}
else if (File.Exists(input))
{
try
{
2020-07-26 23:39:33 -07:00
outputs.Add(new ParentablePath(Path.GetFullPath(input), appendparent ? parentPath : string.Empty));
}
2020-09-15 12:12:13 -07:00
catch (PathTooLongException ex)
{
LoggerImpl.Warning(ex, $"The path for '{input}' was too long");
}
catch (Exception ex)
{
LoggerImpl.Error(ex, $"An exception occurred processing '{input}'");
}
}
}
return outputs;
}
/// <summary>
/// Retrieve a list of files from a directory recursively in proper order
/// </summary>
/// <param name="dir">Directory to parse</param>
2020-08-08 21:53:34 -07:00
/// <param name="pattern">Optional pattern to search for directory names</param>
/// <returns>List with all new files</returns>
2020-08-08 21:53:34 -07:00
public static List<string> GetFilesOrdered(string dir, string pattern = "*")
{
2020-08-08 21:53:34 -07:00
return GetFilesOrderedHelper(dir, new List<string>(), pattern);
}
/// <summary>
/// Retrieve a list of files from a directory recursively in proper order
/// </summary>
/// <param name="dir">Directory to parse</param>
/// <param name="infiles">List representing existing files</param>
2020-08-08 21:53:34 -07:00
/// <param name="pattern">Optional pattern to search for directory names</param>
/// <returns>List with all new files</returns>
2020-08-08 21:53:34 -07:00
private static List<string> GetFilesOrderedHelper(string dir, List<string> infiles, string pattern)
{
// Take care of the files in the top directory
2020-08-08 21:53:34 -07:00
List<string> toadd = Directory.EnumerateFiles(dir, pattern, SearchOption.TopDirectoryOnly).ToList();
toadd.Sort(new NaturalComparer());
infiles.AddRange(toadd);
// Then recurse through and add from the directories
2020-08-08 21:53:34 -07:00
List<string> subDirs = Directory.EnumerateDirectories(dir, pattern, SearchOption.TopDirectoryOnly).ToList();
subDirs.Sort(new NaturalComparer());
foreach (string subdir in subDirs)
{
2020-08-08 21:53:34 -07:00
infiles = GetFilesOrderedHelper(subdir, infiles, pattern);
}
// Return the new list
return infiles;
}
/// <summary>
/// Get all empty folders within a root folder
/// </summary>
/// <param name="root">Root directory to parse</param>
/// <returns>IEumerable containing all directories that are empty, an empty enumerable if the root is empty, null otherwise</returns>
public static List<string> ListEmpty(string root)
{
// Check if the root exists first
if (!Directory.Exists(root))
return null;
// If it does and it is empty, return a blank enumerable
if (Directory.EnumerateFileSystemEntries(root, "*", SearchOption.AllDirectories).Count() == 0)
return new List<string>();
// Otherwise, get the complete list
return Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories)
.Where(dir => Directory.EnumerateFileSystemEntries(dir, "*", SearchOption.AllDirectories).Count() == 0)
.ToList();
}
/// <summary>
/// Try to safely delete a directory, optionally throwing the error
/// </summary>
/// <param name="file">Name of the directory to delete</param>
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
public static bool TryCreateDirectory(string file, bool throwOnError = false)
{
// Now wrap creating the directory
try
{
Directory.CreateDirectory(file);
return true;
}
catch (Exception ex)
{
if (throwOnError)
throw ex;
else
return false;
}
}
/// <summary>
/// Try to safely delete a directory, optionally throwing the error
/// </summary>
/// <param name="file">Name of the directory to delete</param>
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
public static bool TryDelete(string file, bool throwOnError = false)
{
// Check if the directory exists first
if (!Directory.Exists(file))
return true;
// Now wrap deleting the directory
try
{
Directory.Delete(file, true);
return true;
}
catch (Exception ex)
{
if (throwOnError)
throw ex;
else
return false;
}
}
}
}