PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NUnit/util/PathUtils.cs

#
C# | 260 lines | 178 code | 45 blank | 37 comment | 52 complexity | 3521133c9c8f32d0fe34c8004478c094 MD5 | raw file
Possible License(s): GPL-2.0
  1. // ****************************************************************
  2. // Copyright 2002-2003, Charlie Poole
  3. // This is free software licensed under the NUnit license. You may
  4. // obtain a copy of the license at http://nunit.org
  5. // ****************************************************************
  6. using System;
  7. using System.IO;
  8. using System.Text;
  9. using System.Reflection;
  10. using System.Collections;
  11. using System.Runtime.InteropServices;
  12. namespace NUnit.Util
  13. {
  14. /// <summary>
  15. /// Static methods for manipulating project paths, including both directories
  16. /// and files. Some synonyms for System.Path methods are included as well.
  17. /// </summary>
  18. public class PathUtils
  19. {
  20. public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
  21. public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
  22. public const int MAX_PATH = 256;
  23. protected static char DirectorySeparatorChar = Path.DirectorySeparatorChar;
  24. protected static char AltDirectorySeparatorChar = Path.AltDirectorySeparatorChar;
  25. #region Public methods
  26. public static bool IsAssemblyFileType( string path )
  27. {
  28. string extension = Path.GetExtension( path ).ToLower();
  29. return extension == ".dll" || extension == ".exe";
  30. }
  31. /// <summary>
  32. /// Returns the relative path from a base directory to another
  33. /// directory or file.
  34. /// </summary>
  35. public static string RelativePath( string from, string to )
  36. {
  37. if (from == null)
  38. throw new ArgumentNullException (from);
  39. if (to == null)
  40. throw new ArgumentNullException (to);
  41. string toPathRoot = Path.GetPathRoot(to);
  42. if (toPathRoot == null || toPathRoot == string.Empty)
  43. return to;
  44. string fromPathRoot = Path.GetPathRoot(from);
  45. if (!PathsEqual(toPathRoot, fromPathRoot))
  46. return null;
  47. string fromNoRoot = from.Substring(fromPathRoot.Length);
  48. string toNoRoot = to.Substring(toPathRoot.Length);
  49. string[] _from = SplitPath(fromNoRoot);
  50. string[] _to = SplitPath(toNoRoot);
  51. StringBuilder sb = new StringBuilder (Math.Max (from.Length, to.Length));
  52. int last_common, min = Math.Min (_from.Length, _to.Length);
  53. for (last_common = 0; last_common < min; ++last_common)
  54. {
  55. if (!PathsEqual(_from[last_common], _to[last_common]))
  56. break;
  57. }
  58. if (last_common < _from.Length)
  59. sb.Append ("..");
  60. for (int i = last_common + 1; i < _from.Length; ++i)
  61. {
  62. sb.Append (PathUtils.DirectorySeparatorChar).Append ("..");
  63. }
  64. if (sb.Length > 0)
  65. sb.Append (PathUtils.DirectorySeparatorChar);
  66. if (last_common < _to.Length)
  67. sb.Append (_to [last_common]);
  68. for (int i = last_common + 1; i < _to.Length; ++i)
  69. {
  70. sb.Append (PathUtils.DirectorySeparatorChar).Append (_to [i]);
  71. }
  72. return sb.ToString ();
  73. }
  74. /// <summary>
  75. /// Return the canonical form of a path.
  76. /// </summary>
  77. public static string Canonicalize( string path )
  78. {
  79. ArrayList parts = new ArrayList(
  80. path.Split( DirectorySeparatorChar, AltDirectorySeparatorChar ) );
  81. for( int index = 0; index < parts.Count; )
  82. {
  83. string part = (string)parts[index];
  84. switch( part )
  85. {
  86. case ".":
  87. parts.RemoveAt( index );
  88. break;
  89. case "..":
  90. parts.RemoveAt( index );
  91. if ( index > 0 )
  92. parts.RemoveAt( --index );
  93. break;
  94. default:
  95. index++;
  96. break;
  97. }
  98. }
  99. // Trailing separator removal
  100. if (parts.Count > 1 && path.Length > 1 && (string)parts[parts.Count - 1] == "")
  101. parts.RemoveAt(parts.Count - 1);
  102. return String.Join(DirectorySeparatorChar.ToString(), (string[])parts.ToArray(typeof(string)));
  103. }
  104. /// <summary>
  105. /// True if the two paths are the same. However, two paths
  106. /// to the same file or directory using different network
  107. /// shares or drive letters are not treated as equal.
  108. /// </summary>
  109. public static bool SamePath( string path1, string path2 )
  110. {
  111. return string.Compare( Canonicalize(path1), Canonicalize(path2), PathUtils.IsWindows() ) == 0;
  112. }
  113. /// <summary>
  114. /// True if the two paths are the same or if the second is
  115. /// directly or indirectly under the first. Note that paths
  116. /// using different network shares or drive letters are
  117. /// considered unrelated, even if they end up referencing
  118. /// the same subtrees in the file system.
  119. /// </summary>
  120. public static bool SamePathOrUnder( string path1, string path2 )
  121. {
  122. path1 = Canonicalize( path1 );
  123. path2 = Canonicalize( path2 );
  124. int length1 = path1.Length;
  125. int length2 = path2.Length;
  126. // if path1 is longer, then path2 can't be under it
  127. if ( length1 > length2 )
  128. return false;
  129. // if lengths are the same, check for equality
  130. if ( length1 == length2 )
  131. return string.Compare( path1, path2, IsWindows() ) == 0;
  132. // path 2 is longer than path 1: see if initial parts match
  133. if ( string.Compare( path1, path2.Substring( 0, length1 ), IsWindows() ) != 0 )
  134. return false;
  135. // must match through or up to a directory separator boundary
  136. return path2[length1-1] == DirectorySeparatorChar ||
  137. path2[length1] == DirectorySeparatorChar;
  138. }
  139. public static string Combine( string path1, params string[] morePaths )
  140. {
  141. string result = path1;
  142. foreach( string path in morePaths )
  143. result = Path.Combine( result, path );
  144. return result;
  145. }
  146. // TODO: This logic should be in shared source
  147. public static string GetAssemblyPath( Assembly assembly )
  148. {
  149. string uri = assembly.CodeBase;
  150. // If it wasn't loaded locally, use the Location
  151. if ( !uri.StartsWith( Uri.UriSchemeFile ) )
  152. return assembly.Location;
  153. return GetAssemblyPathFromFileUri( uri );
  154. }
  155. // Separate method for testability
  156. public static string GetAssemblyPathFromFileUri( string uri )
  157. {
  158. // Skip over the file://
  159. int start = Uri.UriSchemeFile.Length + Uri.SchemeDelimiter.Length;
  160. if ( PathUtils.DirectorySeparatorChar == '\\' )
  161. {
  162. if ( uri[start] == '/' && uri[start+2] == ':' )
  163. ++start;
  164. }
  165. else
  166. {
  167. if ( uri[start] != '/' )
  168. --start;
  169. }
  170. return uri.Substring( start );
  171. }
  172. #endregion
  173. #region Helper Methods
  174. private static bool IsWindows()
  175. {
  176. return PathUtils.DirectorySeparatorChar == '\\';
  177. }
  178. private static string[] SplitPath(string path)
  179. {
  180. char[] separators = new char[] { PathUtils.DirectorySeparatorChar, PathUtils.AltDirectorySeparatorChar };
  181. #if NET_2_0
  182. return path.Split(separators, StringSplitOptions.RemoveEmptyEntries);
  183. #else
  184. string[] trialSplit = path.Split(separators);
  185. int emptyEntries = 0;
  186. foreach(string piece in trialSplit)
  187. if (piece == string.Empty)
  188. emptyEntries++;
  189. if (emptyEntries == 0)
  190. return trialSplit;
  191. string[] finalSplit = new string[trialSplit.Length - emptyEntries];
  192. int index = 0;
  193. foreach(string piece in trialSplit)
  194. if (piece != string.Empty)
  195. finalSplit[index++] = piece;
  196. return finalSplit;
  197. #endif
  198. }
  199. private static bool PathsEqual(string path1, string path2)
  200. {
  201. #if NET_2_0
  202. if (PathUtils.IsWindows())
  203. return path1.Equals(path2, StringComparison.InvariantCultureIgnoreCase);
  204. else
  205. return path1.Equals(path2, StringComparison.InvariantCulture);
  206. #else
  207. if (PathUtils.IsWindows())
  208. return path1.ToLower().Equals(path2.ToLower());
  209. else
  210. return path1.Equals(path2);
  211. #endif
  212. }
  213. #endregion
  214. }
  215. }