/Utilities/Helpers/DirectoryHelper.cs
C# | 803 lines | 498 code | 91 blank | 214 comment | 39 complexity | 5b0d4aa036343df81646d165e75a79c3 MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Threading;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Helpers
- {
- /// <summary>
- /// Directory helper
- /// </summary>
- public static class DirectoryHelper
- {
- #region Delegates
- internal delegate bool ExistsDelegate(string directory);
-
- /// <summary>
- /// Delegate definition for getting the base directory.
- /// </summary>
- /// <returns>String with the base directory</returns>
- internal delegate string GetBaseDirectoryDelegate();
-
- /// <summary>
- /// Delegate definition for getting the current directory.
- /// </summary>
- /// <returns>String with the current directory</returns>
- internal delegate string GetCurrentDirectoryDelegate();
-
- /// <summary>
- /// Delegate definition for setting the current directory.
- /// </summary>
- /// <param name="newDirectory">New Directory to switch into</param>
- internal delegate void SetCurrentDirectoryDelegate(string newDirectory);
-
- /// <summary>
- /// Create a directory with the specific path.
- /// </summary>
- /// <param name="directoryPath">Directory path to create</param>
- internal delegate void CreateDirectoryDelegate(string directoryPath);
-
- /// <summary>
- /// just Directory.GetFiles).
- /// </summary>
- /// <param name="path">File path for the search</param>
- /// <param name="searchPattern">Search Pattern</param>
- internal delegate string[] GetFilesDelegate(string path,
- string searchPattern);
-
- internal delegate string[] GetDirectoriesDelegate(string path,
- string searchPattern);
-
- internal delegate string[] GetDirectoriesRecursiveDelegate(string path,
- string searchPattern);
-
- internal delegate void DeleteDelegate(string path);
- #endregion
-
- #region Exists (Static)
- /// <summary>
- /// Helper method to figure out if a directory exists, will just call
- /// MethodAccessException, there we use the isolated storage instead.
- /// </summary>
- /// <param name="directory">
- /// Directory to check for. If this is null or empty, true is returned (the
- /// current path we are in obviously exists).
- /// </param>
- /// <returns>True if the directory path exists, false otherwise</returns>
- public static bool Exists(string directory)
- {
- if (String.IsNullOrEmpty(directory))
- {
- return true;
- }
-
- return ExistsCallback(directory);
- }
- #endregion
-
- #region GetBaseDirectory (Static)
- /// <summary>
- /// Get base directory where the application was started, is usually the
- /// same as GetCurrentDirectory, but can differ if current directory was
- /// changed (e.g. via SetCurrentDirectory).
- /// </summary>
- /// <returns>String with the base directory</returns>
- public static string GetBaseDirectory()
- {
- return GetBaseDirectoryCallback();
- }
- #endregion
-
- #region GetCurrentDirectory (Static)
- /// <summary>
- /// Get current directory, just uses Directory.GetCurrentDirectory except
- /// </summary>
- /// <returns>String with the current directory</returns>
- public static string GetCurrentDirectory()
- {
- return GetCurrentDirectoryCallback();
- }
- #endregion
-
- #region SetCurrentDirectory (Static)
- /// <summary>
- /// Set current directory, just uses Directory.SetCurrentDirectory except
- /// </summary>
- /// <param name="newDirectory">New Directory to switch into</param>
- public static void SetCurrentDirectory(string newDirectory)
- {
- SetCurrentDirectoryCallback(newDirectory);
- }
- #endregion
-
- #region CreateDirectory (Static)
- /// <summary>
- /// Create a directory with the specific path.
- /// </summary>
- /// <param name="directoryPath">Directory path to create</param>
- /// <param name="deleteIfExists">
- /// If the directory already exists, then delete it or not.
- /// </param>
- public static void CreateDirectory(string directoryPath,
- bool deleteIfExists = false)
- {
- bool existsAlready = Exists(directoryPath);
- if (deleteIfExists &&
- existsAlready)
- {
- Delete(directoryPath, true);
- // Wait a bit to not confuse the OS with the creation of the directory
- // we just deleted! If we don't do this the creation below might fail.
- Thread.Sleep(10);
- }
-
- // We cannot create the current relative directory (empty string)
- // And we only need to create if the directory does not exist yet.
- if (String.IsNullOrEmpty(directoryPath) == false &&
- (deleteIfExists ||
- existsAlready == false))
- {
- CreateDirectoryCallback(directoryPath);
- }
- }
- #endregion
-
- #region GetFiles (Static)
- /// <summary>
- /// Get files helper method.
- /// </summary>
- /// <param name="path">File path for the search</param>
- /// <param name="searchPattern">Search Pattern</param>
- /// <returns>
- /// Files in the directory matching searchPattern as filename string list
- /// with full file paths.
- /// </returns>
- public static string[] GetFiles(string path, string searchPattern)
- {
- // If path does not exist, Directory.GetFiles would throw an exception
- if (String.IsNullOrEmpty(path) ||
- Exists(path) == false)
- {
- return new string[0];
- }
- return GetFilesCallback(path, searchPattern);
- }
- #endregion
-
- #region GetFilesRecursive (Static)
- /// <summary>
- /// Get files function with recursive file searching in sub directories.
- /// </summary>
- /// <param name="path">File path for the start of the search</param>
- /// <param name="searchPattern">Search Pattern</param>
- /// <returns>
- /// Files in the directory and any sub directory matching searchPattern as
- /// filename string list (with full absolute file paths).
- /// </returns>
- public static string[] GetFilesRecursive(string path,
- string searchPattern)
- {
- // check null or empty and path exists
- if (String.IsNullOrEmpty(path) ||
- Exists(path) == false)
- {
- return new string[0];
- }
-
- List<string> files = new List<string>();
-
- try
- {
- // find all directories in the current
- foreach (string s in GetDirectories(path))
- {
- // add the search results of the next folder
- files.AddRange(GetFilesRecursive(s, searchPattern));
- }
-
- // add the files of the current directory
- files.AddRange(GetFiles(path, searchPattern));
- }
- catch (Exception ex)
- {
- Log.Warning("GetFiles failed for the following reason:" + ex);
- }
-
- // return the collected files list
- return files.ToArray();
- }
- #endregion
-
- #region GetFilesMultiPattern (Static)
- /// <summary>
- /// Same as normal GetFiles but with the option to use multi patterns,
- /// e.g. "*.txt|*.wma".
- /// </summary>
- /// <param name="path">Path to search for files in.</param>
- /// <param name="searchPattern">Multiple pattern separated by an |</param>
- /// <param name="recursive">Recursive file search</param>
- /// <returns>Array of found files.</returns>
- public static string[] GetFilesMultiPattern(string path,
- string searchPattern, bool recursive = false)
- {
- string[] patterns = searchPattern.Split('|');
- List<string> foundFiles = new List<string>();
- foreach (string pattern in patterns)
- {
- if (recursive)
- {
- foundFiles.AddRange(GetFilesRecursive(path, pattern));
- }
- else
- {
- foundFiles.AddRange(GetFiles(path, pattern));
- }
- }
-
- return foundFiles.ToArray();
- }
- #endregion
-
- #region GetDirectories (Static)
- /// <summary>
- /// Get the directories in the given path.
- /// </summary>
- /// <param name="path">Path</param>
- /// <returns>Array of sub directories of path</returns>
- public static string[] GetDirectories(string path)
- {
- return GetDirectories(path, "*");
- }
-
- /// <summary>
- /// Get the directories in the given path.
- /// </summary>
- /// <param name="path">Path</param>
- /// <param name="searchPattern">Search pattern to find specific
- /// directories only.</param>
- /// <returns>Array of sub directories of path</returns>
- public static string[] GetDirectories(string path, string searchPattern)
- {
- if (Exists(path) == false)
- {
- return new string[0];
- }
-
- return GetDirectoriesCallback(path, searchPattern);
- }
- #endregion
-
- #region GetDirectoriesRecursive (Static)
- /// <summary>
- /// Get all directories and sub directories in the given path recursively.
- /// </summary>
- /// <param name="path">Path</param>
- /// <returns>List of all directories found</returns>
- public static string[] GetDirectoriesRecursive(string path)
- {
- return GetDirectoriesRecursive(path, "*");
- }
-
- /// <summary>
- /// Get all directories and sub directories in the given path recursively.
- /// </summary>
- /// <param name="path">Path</param>
- /// <param name="searchPattern">Search Pattern</param>
- /// <returns>List of all directories found</returns>
- public static string[] GetDirectoriesRecursive(string path,
- string searchPattern)
- {
- if (Exists(path) == false)
- {
- return new string[0];
- }
-
- return GetDirectoriesRecursiveCallback(path, searchPattern);
- }
- #endregion
-
- #region GetParentDirectory (Static)
- /// <summary>
- /// Gets the parent directory of the given directory.
- /// </summary>
- /// <param name="directory">The path of the current folder</param>
- /// <param name="parentDirectory">The path of the parent directory.</param>
- /// <returns>Returns 'true' if there is a parent directory.</returns>
- public static bool GetParentDirectory(this string directory,
- out string parentDirectory)
- {
- parentDirectory = FileHelper.GetDirectoryPath(directory);
-
- return parentDirectory != directory;
- }
- #endregion
-
- #region ComparePaths (Static)
- /// <summary>
- /// Compare two paths, ignoring if they use \\ or / and if
- /// something is written in big or small letters. We also check the full
- /// path so if we have something like .. or . this won't affect the
- /// comparison.
- /// </summary>
- /// <param name="path1">First path.</param>
- /// <param name="path2">Second path.</param>
- /// <returns>True if the paths are equal.</returns>
- public static bool ComparePaths(string path1, string path2)
- {
- // Validation
- if (String.IsNullOrEmpty(path1) ||
- String.IsNullOrEmpty(path2))
- {
- return false;
- }
-
- DirectoryInfo info1 = new DirectoryInfo(path1);
- DirectoryInfo info2 = new DirectoryInfo(path2);
-
- return String.Compare(
- info1.FullName.TrimEnd('\\'),
- info2.FullName.TrimEnd('\\'),
- StringComparison.InvariantCultureIgnoreCase) == 0 &&
- String.Compare(
- Path.GetFullPath(path1).ToUpperInvariant().TrimEnd('\\'),
- Path.GetFullPath(path2).ToUpperInvariant().TrimEnd('\\'),
- StringComparison.InvariantCultureIgnoreCase) == 0;
-
- //path1 = path1.Replace("\\", "/").ToLower();
- //path2 = path2.Replace("\\", "/").ToLower();
- //return path1 == path2;
- }
- #endregion
-
- #region IncludeTrailingBackslash (Static)
- /// <summary>
- /// Include trailing backslash. Makes sure the directory ends with "\".
- /// </summary>
- /// <param name="directory">Directory</param>
- /// <returns>String that always ends with a backslash</returns>
- public static string IncludeTrailingBackslash(string directory)
- {
- if (directory.Length == 0 ||
- directory[directory.Length - 1] != '\\')
- {
- directory += @"\";
- }
- return directory;
- }
- #endregion
-
- #region ExcludeTrailingBackslash (Static)
- /// <summary>
- /// Exclude last trailing backslash from a directory.
- /// </summary>
- /// <param name="directory">Directory</param>
- /// <returns>String without a trailing backslash</returns>
- public static string ExcludeTrailingBackslash(string directory)
- {
- if (directory[directory.Length - 1] == '\\')
- {
- return directory.Substring(0, directory.Length - 1);
- }
- return directory;
- }
- #endregion
-
- #region CopyDirectory (Static)
- /// <summary>
- /// Copy directory and all files over to destinationPath.
- /// </summary>
- /// <param name="destinationPath">Destination Path</param>
- /// <param name="sourcePath">Source Path</param>
- /// <returns>True if the directory was copied successfully</returns>
- public static bool CopyDirectory(string sourcePath,
- string destinationPath)
- {
- bool ret = false;
- try
- {
- string separator = Path.DirectorySeparatorChar.ToString();
- sourcePath =
- sourcePath.EndsWith(separator)
- ? sourcePath
- : sourcePath + separator;
-
- destinationPath =
- destinationPath.EndsWith(separator)
- ? destinationPath
- : destinationPath + separator;
-
- if (Exists(sourcePath))
- {
- if (Exists(destinationPath) == false)
- {
- CreateDirectory(destinationPath);
- }
-
- foreach (string fls in GetFiles(sourcePath, "*"))
- {
- FileInfo flinfo = new FileInfo(fls);
- flinfo.CopyTo(destinationPath + flinfo.Name, true);
- if (FileHelper.CompareFiles(destinationPath + flinfo.Name, fls) ==
- false)
- {
- throw new Exception(
- "Failed to copy a file (" +flinfo.Name +
- "). Source and destination files are not equal!");
- }
- }
- ret = true;
- foreach (string drs in GetDirectories(sourcePath))
- {
- DirectoryInfo drinfo = new DirectoryInfo(drs);
- if (CopyDirectory(drs, destinationPath + drinfo.Name) == false)
- {
- ret = false;
- }
- }
- }
- }
- catch // (Exception ex)
- {
- ret = false;
- }
-
- return ret;
- }
- #endregion
-
- #region MoveDirectory (Static)
- /// <summary>
- /// Move directory and all files in it to destinationPath.
- /// </summary>
- /// <param name="destinationPath">Destination Path</param>
- /// <param name="sourcePath">Source Path</param>
- /// <returns>True if the move was successful</returns>
- public static bool MoveDirectory(string sourcePath,
- string destinationPath)
- {
- bool ret = false;
- try
- {
- string separator = Path.DirectorySeparatorChar.ToString();
- sourcePath = sourcePath.EndsWith(separator)
- ? sourcePath
- : sourcePath + separator;
-
- destinationPath = destinationPath.EndsWith(separator)
- ? destinationPath
- : destinationPath + separator;
-
- if (Exists(sourcePath))
- {
- if (Exists(destinationPath) == false)
- {
- CreateDirectory(destinationPath);
- }
-
- foreach (string fls in GetFiles(sourcePath, "*"))
- {
- FileInfo flinfo = new FileInfo(fls);
- flinfo.MoveTo(destinationPath + flinfo.Name);
- }
-
- foreach (string drs in Directory.GetDirectories(sourcePath))
- {
- DirectoryInfo drinfo = new DirectoryInfo(drs);
- if (MoveDirectory(drs, destinationPath + drinfo.Name) == false)
- {
- ret = false;
- }
- }
- }
-
- if (Exists(sourcePath))
- {
- SafeDelete(sourcePath);
- }
- ret = true;
- }
- catch // (Exception ex)
- {
- ret = false;
- }
-
- return ret;
- }
- #endregion
-
- #region SafeDelete (Static)
- /// <summary>
- /// Delete directory and warn if we are unable to delete files.
- /// </summary>
- /// <param name="path">Path</param>
- /// <returns>True if the deletion succeeded</returns>
- public static bool SafeDelete(string path)
- {
- return Delete(path, true);
- }
- #endregion
-
- #region Delete (Static)
- /// <summary>
- /// Delete directory and optionally warn if we are unable to delete files.
- /// </summary>
- /// <param name="path">Path to delete</param>
- /// <param name="warnIfFailing">
- /// Warn if any file fails to be deleted (usually happens when files are
- /// still open and locked).
- /// </param>
- /// <returns>
- /// True if the deletion succeeded, if the directory does not exist this
- /// method simply returns false.
- /// </returns>
- public static bool Delete(string path, bool warnIfFailing)
- {
- if (Exists(path) == false)
- {
- return true;
- }
-
- try
- {
- foreach (string file in GetFilesRecursive(path, "*.*"))
- {
- try
- {
- FileHelper.SafeDelete(file);
- }
- catch (Exception)
- {
- if (warnIfFailing)
- {
- Log.Warning("Unable to delete file: " + file);
- }
- }
- }
-
- DeleteCallback(path);
-
- return true;
- }
- catch (Exception ex)
- {
- if (warnIfFailing)
- {
- Log.Warning("Failed to delete directory " + path + ": " + ex);
- }
- return false;
- }
- }
- #endregion
-
- #region Internal
-
- #region ExistsCallback (Internal)
- internal static ExistsDelegate ExistsCallback;
- #endregion
-
- #region GetBaseDirectoryCallback (Internal)
- /// <summary>
- /// Callback for getting the base directory. On Windows this is just
- /// Directory.GetBaseDirectory.
- /// </summary>
- internal static GetBaseDirectoryDelegate GetBaseDirectoryCallback;
- #endregion
-
- #region GetCurrentDirectoryCallback (Internal)
- /// <summary>
- /// Callback for getting the current directory. On Windows this is just
- /// Directory.GetCurrentDirectory.
- /// </summary>
- internal static GetCurrentDirectoryDelegate GetCurrentDirectoryCallback;
- #endregion
-
- #region SetCurrentDirectoryCallback (Internal)
- /// <summary>
- /// Callback for setting the current directory. On Windows this is just
- /// Directory.SetCurrentDirectory.
- /// </summary>
- internal static SetCurrentDirectoryDelegate SetCurrentDirectoryCallback;
- #endregion
-
- #region CreateDirectoryCallback (Internal)
- /// <summary>
- /// Callback for creating a new directory. On Windows this is just
- /// Directory.Create.
- /// </summary>
- internal static CreateDirectoryDelegate CreateDirectoryCallback;
- #endregion
-
- #region GetFilesCallback (Internal)
- /// <summary>
- /// Callback for getting all files in a directory. On Windows this is just
- /// Directory.GetFiles.
- /// </summary>
- internal static GetFilesDelegate GetFilesCallback;
- #endregion
-
- #region GetDirectoriesCallback (Internal)
- internal static GetDirectoriesDelegate GetDirectoriesCallback;
- #endregion
-
- #region GetDirectoriesRecursiveCallback (Internal)
- internal static GetDirectoriesRecursiveDelegate
- GetDirectoriesRecursiveCallback;
- #endregion
-
- #region DeleteCallback (Internal)
- internal static DeleteDelegate DeleteCallback;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Static constructor to setup all the needed callbacks.
- /// </summary>
- static DirectoryHelper()
- {
- ExistsCallback = Directory.Exists;
- SetCurrentDirectoryCallback = Directory.SetCurrentDirectory;
- GetDirectoriesCallback = Directory.GetDirectories;
- GetCurrentDirectoryCallback = Directory.GetCurrentDirectory;
- GetFilesCallback = Directory.GetFiles;
-
- #region CreateDirectoryCallback
- CreateDirectoryCallback = delegate(string directoryPath)
- {
- Directory.CreateDirectory(directoryPath);
- };
- #endregion
-
- #region GetBaseDirectoryCallback
- GetBaseDirectoryCallback = delegate
- {
- return AppDomain.CurrentDomain.BaseDirectory;
- };
- #endregion
-
- #region GetDirectoriesRecursiveCallback
- GetDirectoriesRecursiveCallback = delegate(string path,
- string searchPattern)
- {
- return Directory.GetDirectories(path, searchPattern,
- SearchOption.AllDirectories);
- };
- #endregion
-
- #region DeleteCallback
- DeleteCallback = delegate(string path)
- {
- Directory.Delete(path, true);
- };
- #endregion
- }
- #endregion
-
- /// <summary>
- /// Tests for the DirectoryHelper class
- /// </summary>
- internal class DirectoryHelperTests
- {
- #region CopyDir (Static)
- /// <summary>
- /// Copy directory. Note: Too slow for a dynamic unit test.
- /// </summary>
- [Test, Category("LongRunning")]
- public static void CopyDir()
- {
- // Only do this test if C:\testing and C:\copytest do not exist!
- Assert.False(Directory.Exists("C:\\testing\\"));
- Assert.False(Directory.Exists("C:\\copytest\\"));
-
- Directory.CreateDirectory("C:\\testing\\");
- Directory.CreateDirectory("C:\\testing\\bla\\");
- File.Create("C:\\testing\\test.txt").Close();
- File.Create("C:\\testing\\bla\\test.txt").Close();
-
- Assert.True(CopyDirectory("C:\\testing\\", "C:\\copytest\\"),
- "Copy Directory");
-
- Assert.True(File.Exists("C:\\copytest\\test.txt"), "File Exists");
- Assert.True(File.Exists("C:\\copytest\\bla\\test.txt"), "File Exists");
-
- Directory.Delete("C:\\testing\\", true);
- Directory.Delete("C:\\copytest\\", true);
- }
- #endregion
-
- #region GetFilesRecursive (Static)
- /// <summary>
- /// Test GetFilesRecursive
- /// </summary>
- [Test, Category("LongRunning")]
- public static void GetFilesRecursive()
- {
- string deltaBasePath =
- Exists(@"C:\code\Delta")
- ? @"C:\code\Delta"
- : @"C:\Development\Delta";
- string rootPath = deltaBasePath + @"\Engine\";
-
- string[] result = DirectoryHelper.GetFilesRecursive(rootPath, "*.cs");
- Assert.True((rootPath + "Application.cs").Contains(result));
- Assert.False((rootPath + "blubbb.cs").Contains(result));
-
- result = DirectoryHelper.GetFilesRecursive(rootPath,
- "Delta.Engine.csproj");
- Assert.Equal(result.Length, 1);
- Assert.Equal(result[0], rootPath + "Delta.Engine.csproj");
- }
- #endregion
-
- #region TestGetFilesMultiPattern (Static)
- /// <summary>
- /// Test get files multi pattern
- /// </summary>
- [Test, Category("LongRunning")]
- public static void TestGetFilesMultiPattern()
- {
- string[] files = GetFilesMultiPattern(@"C:\code\Delta\",
- "*.sln|*.suo");
- foreach (string file in files)
- {
- Console.WriteLine(file);
- }
- }
- #endregion
-
- #region ComparePaths (Static)
- /// <summary>
- /// Test the ComparePaths method.
- /// </summary>
- [Test]
- public static void ComparePaths()
- {
- Assert.True(DirectoryHelper.ComparePaths(
- "C:\\code\\Delta", "C:\\code\\Delta"));
-
- Assert.True(DirectoryHelper.ComparePaths(
- "C:\\code\\Delta", "C:/code/Delta"));
-
- Assert.True(DirectoryHelper.ComparePaths(
- "c:\\code\\delta", "C:/CODE/DELTA"));
-
- Assert.False(DirectoryHelper.ComparePaths(
- "C:\\code\\Delta", "C:\\code\\Delt"));
-
- // Special cases
- Assert.True(DirectoryHelper.ComparePaths(
- "C:\\code\\Delta\\..\\..\\.\\code\\Delta", "C:\\code\\Delta"));
-
- Assert.True(DirectoryHelper.ComparePaths(
- "C:/code\\Delta", "C:\\code/Delta"));
-
- Assert.True(DirectoryHelper.ComparePaths(
- "C:/code\\..\\code\\Delta", "C:\\code/./Delta"));
- }
- #endregion
-
- #region GetParentDirectory
- /// <summary>
- /// Get parent directory
- /// </summary>
- [Test]
- public void GetParentDirectory()
- {
- string path = @"C:\Windows\System32";
-
- string parentPath;
- Assert.True(path.GetParentDirectory(out parentPath));
- Assert.Equal(parentPath, @"C:\Windows");
-
- Assert.True(parentPath.GetParentDirectory(out parentPath));
- Assert.Equal(parentPath, @"C:");
-
- Assert.False(parentPath.GetParentDirectory(out parentPath));
- Assert.Equal(parentPath, @"C:");
- }
- #endregion
- }
- }
- }