20using System.Collections.Generic;
31 private readonly
string _path;
70 public string Name => Path.GetFileName(_path);
80 public string Extension => Path.GetExtension(_path);
116 var stringComparison =
PathUtils.
HasWinRoot(_path) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
117 return string.Equals(_path, other._path, stringComparison);
132 if (ReferenceEquals(objA:
null, obj))
134 if (ReferenceEquals(
this, obj))
136 if (obj.GetType() != GetType())
143 return _path?.GetHashCode() ?? 0;
148 return ((IFormattable)
this).ToString(format:
null, formatProvider:
null);
155 string IFormattable.ToString(
string format, IFormatProvider formatProvider)
157 var path = _path.WithUnixSeparator();
163 _ =>
throw new ArgumentException($
"Format '{format}' is not recognized")
184 Path.GetRelativePath(root,
self).WithUnixSeparator();
190 Path.GetRelativePath(
self, subfolder).WithUnixSeparator();
217 public static IEnumerable<AbsolutePath>
Files(
this AbsolutePath path,
string pattern =
"*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
218 => Directory.EnumerateFiles(path, pattern, searchOption)
219 .Select(p => p.AsPath());
227 public static IEnumerable<AbsolutePath>
Directories(
this AbsolutePath path,
string pattern =
"*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
228 => Directory.EnumerateDirectories(path, pattern, searchOption)
229 .Select(p => p.AsPath());
235 => alternativeExtensions.Append(extension)
236 .Any(e => path.Extension.Equals(e, StringComparison.InvariantCultureIgnoreCase));
242 => path.Parent / Path.ChangeExtension(path.Name, extension);
250 if (!path.DirectoryExists())
251 Directory.CreateDirectory(path);
255 private static List<AbsolutePath> FileSystemTask(
256 Action<string, string> task,
261 var output =
new List<AbsolutePath>();
262 if (path.FileExists())
264 to.
Parent.CreateDirectory();
268 else if (path.DirectoryExists())
270 foreach (var file
in path.Files(pattern, SearchOption.AllDirectories))
272 var dst = to / file.RelativeToBase(path);
273 output.AddRange(FileSystemTask(task, file, dst));
288 (src, dst) => File.Copy(src, dst,
true),
300 => path.Copy(intoDirectory / path.
Name, pattern);
311 (src, dst) => File.Move(src, dst,
true),
323 => path.Move(intoDirectory / path.
Name, pattern);
360 private static bool IsSameDirectory(
string pathPart)
361 => pathPart?.Length == 1 &&
362 pathPart[index: 0] ==
'.';
364 private static bool IsUpwardsDirectory(
string pathPart)
365 => pathPart?.Length == 2 &&
366 pathPart[index: 0] ==
'.' &&
367 pathPart[index: 1] ==
'.';
370 => root?.Length == 2 &&
371 char.IsLetter(root[index: 0]) &&
372 root[index: 1] ==
':';
375 => root?.Length == 1 &&
379 => root?.Length >= 3 &&
382 root.Skip(count: 2).All(
char.IsLetterOrDigit);
384 private static string GetHeadPart(
string str,
int count) =>
new((str ??
string.Empty).Take(count).ToArray());
396 return GetHeadPart(path, count: 1);
399 return GetHeadPart(path, count: 2);
403 var separatorIndex = path.IndexOf(
UncSeparator, startIndex: 2);
404 return separatorIndex == -1 ? path : GetHeadPart(path, separatorIndex);
412 private static char GetSeparator(
string path)
427 return Path.DirectorySeparatorChar;
430 private static string Trim(
string path)
440 public static string Combine(
string left,
string right,
char? separator =
null)
445 if (
string.IsNullOrWhiteSpace(left))
447 if (
string.IsNullOrWhiteSpace(right))
448 return !
IsWinRoot(left) ? left :
$@"{left}\";
450 separator ??= GetSeparator(left);
453 return $@"{left}\{right}";
455 return $
"{left}{right}";
457 return $@"{left}\{right}";
459 return $
"{left}{separator}{right}";
464 path ??=
string.Empty;
465 separator ??= GetSeparator(path);
468 var tail = root ==
null ? path : path.Substring(root.Length);
469 var tailParts = tail.Split(
AllSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
470 for (var i = 0; i < tailParts.Count;)
472 var part = tailParts[i];
473 if (IsUpwardsDirectory(part))
475 if (tailParts.Take(i).All(IsUpwardsDirectory))
481 tailParts.RemoveAt(i);
482 tailParts.RemoveAt(i - 1);
487 if (IsSameDirectory(part))
489 tailParts.RemoveAt(i);
496 return Combine(root,
string.Join(separator.Value, tailParts), separator);
The API NUKE has for AbsolutePath relies heavily on extension methods. In fact if file system operati...
static AbsolutePath WithExtension(this AbsolutePath path, string extension)
Replace extension of left-side with~ or add given extension
static List< AbsolutePath > CopyInto(this AbsolutePath path, AbsolutePath intoDirectory, string pattern="*")
Copy a file or a directory recursively into a target folder.
static List< AbsolutePath > MoveInto(this AbsolutePath path, AbsolutePath intoDirectory, string pattern="*")
Move a file or a directory recursively into a target folder.
static List< AbsolutePath > Move(this AbsolutePath path, AbsolutePath to, string pattern="*")
Move a file or a directory recursively to be the target path.
static string BaseRelativeTo(this AbsolutePath self, AbsolutePath subfolder)
Return a path connecting from left side as a base to the right side as target.
static AbsolutePath ExistingFile(this AbsolutePath path)
Returns null if designated file doesn't exist. This can be used in null-propagating expressions witho...
static IEnumerable< AbsolutePath > Directories(this AbsolutePath path, string pattern="*", SearchOption searchOption=SearchOption.TopDirectoryOnly)
Return all subfolders in a directory.
static AbsolutePath GetRoot(this AbsolutePath self)
static bool IsRoot(this AbsolutePath self)
static AbsolutePath ExistingDirectory(this AbsolutePath path)
Returns null if designated directory doesn't exist. This can be used in null-propagating expressions ...
static bool HasExtension(this AbsolutePath path, string extension, params string[] alternativeExtensions)
Returns true if path ends in any of the given extensions. Input extensions should have leading .
static bool DirectoryExists(this AbsolutePath path)
static List< AbsolutePath > Copy(this AbsolutePath path, AbsolutePath to, string pattern="*")
Copy a file or a directory recursively to be the target path.
static string RelativeToBase(this AbsolutePath self, AbsolutePath root)
Return a path connecting from right side as a base to the left side as target.
static bool FileExists(this AbsolutePath path)
static AbsolutePath CreateDirectory(this AbsolutePath path)
Creates a new directory or does nothing if that's already exists.
static IEnumerable< AbsolutePath > Files(this AbsolutePath path, string pattern="*", SearchOption searchOption=SearchOption.TopDirectoryOnly)
Return all files in a directory.
A simplified copy of NUKE's own AbsolutePath class https://github.com/nuke-build/nuke/blob/develop/so...
override string ToString()
AbsolutePath Parent
The ancestor of this path (..)
string Name
Get the filename (with extension) or the directory name.
static AbsolutePath operator+(AbsolutePath left, string right)
Append a piece of string to this AbsolutePath without any intersperse.
bool Equals(AbsolutePath other)
override bool Equals(object obj)
override int GetHashCode()
string NameWithoutExtension
Get the filename (without extension)
static bool operator==(AbsolutePath a, AbsolutePath b)
static AbsolutePath Create(string path)
Create an AbsolutePath from a string.
string Extension
Get the extension of the filename.
static bool operator!=(AbsolutePath a, AbsolutePath b)
static AbsolutePath operator/(AbsolutePath left, Range range)
Use completely valid C# syntax MyPath/ .. to access ancestor.
Support utilities for AbsolutePath.
static bool HasWinRoot(string path)
static readonly char[] AllSeparators
static bool IsUncRoot(string root)
static AbsolutePath AsPath(this FileReference input)
Convert a left-side FileReference to an AbsolutePath. In fact this is the recommended way to create a...
static bool HasUnixRoot(string path)
static AbsolutePath AsPath(this string input)
Convert a left-side string to an AbsolutePath. In fact this is the recommended way to create an insta...
static string GetPathRoot(string path)
static AbsolutePath AsPath(this DirectoryReference input)
Convert a left-side DirectoryReference to an AbsolutePath. In fact this is the recommended way to cre...
static bool HasUncRoot(string path)
static bool HasPathRoot(string path)
static string NormalizePath(string path, char? separator=null)
static string WithUnixSeparator(this string input)
static bool IsWinRoot(string root)
static string Combine(string left, string right, char? separator=null)
static bool IsUnixRoot(string root)