示例#1
0
        /// <exception cref="ArgumentException">running on Windows host, and unmanaged call failed</exception>
        /// <exception cref="FileNotFoundException">running on Windows host, and either path is not a regular file or directory</exception>
        /// <remarks>Algorithm for Windows taken from https://stackoverflow.com/a/485516/7467292</remarks>
        public static string GetRelativePath(string fromPath, string toPath)
        {
            if (OSTailoredCode.IsUnixHost)
            {
#if true
                return(PathManager.IsSubfolder(toPath, fromPath)
                                        ? "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{toPath}\" \"{fromPath}\"", $"invalid path {fromPath} or missing realpath binary")
                                        : fromPath);
#else // written for Unix port but may be useful for .NET Core
                // algorithm taken from https://stackoverflow.com/a/340454/7467292
                var dirSepChar = Path.DirectorySeparatorChar;
                var fromUri    = new Uri(fromPath.EndsWith(dirSepChar.ToString()) ? fromPath : fromPath + dirSepChar);
                var toUri      = new Uri(toPath.EndsWith(dirSepChar.ToString()) ? toPath : toPath + dirSepChar);
                if (fromUri.Scheme != toUri.Scheme)
                {
                    return(toPath);
                }

                var relativePath = Uri.UnescapeDataString(fromUri.MakeRelativeUri(toUri).ToString());
                return((toUri.Scheme.Equals(Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase)
                                        ? relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
                                        : relativePath
                        ).TrimEnd(dirSepChar));
#endif
            }
示例#2
0
        /// <summary>
        /// Takes an absolute path and attempts to convert it to a relative, based on the system,
        /// or global base if no system is supplied, if it is not a subfolder of the base, it will return the path unaltered
        /// </summary>
        public static string TryMakeRelative(string absolutePath, string system = null)
        {
            var parentPath = string.IsNullOrWhiteSpace(system)
                                ? GetGlobalBasePathAbsolute()
                                : MakeAbsolutePath(GetPlatformBase(system), system);

#if true
            if (!IsSubfolder(parentPath, absolutePath))
            {
                return(absolutePath);
            }

            return(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
                                ? absolutePath.Replace(parentPath, ".")
                                : "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{parentPath}\" \"{absolutePath}\"", $"invalid path {absolutePath} or missing realpath binary"));
#else // written for Unix port but may be useful for .NET Core
            if (!IsSubfolder(parentPath, absolutePath))
            {
                return(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows ||
                       parentPath.TrimEnd('.') != $"{absolutePath}/"
                                                ? absolutePath
                                                : ".");
            }

            return(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
                                ? absolutePath.Replace(parentPath, ".")
                                : absolutePath.Replace(parentPath.TrimEnd('.'), "./"));
#endif
        }
        /// <summary>
        /// Takes an absolute path and attempts to convert it to a relative, based on the system,
        /// or global base if no system is supplied, if it is not a subfolder of the base, it will return the path unaltered
        /// </summary>
        public static string TryMakeRelative(this PathEntryCollection collection, string absolutePath, string system = null)
        {
            var parentPath = string.IsNullOrWhiteSpace(system)
                                ? collection.GlobalBaseAbsolutePath()
                                : collection.AbsolutePathFor(collection.BaseFor(system), system);

#if true
            if (!absolutePath.IsSubfolderOf(parentPath))
            {
                return(absolutePath);
            }

            return(OSTailoredCode.IsUnixHost
                                ? "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{parentPath}\" \"{absolutePath}\"", $"invalid path {absolutePath} or missing realpath binary")
                                : absolutePath.Replace(parentPath, "."));
#else // written for Unix port but may be useful for .NET Core
            if (!IsSubfolder(parentPath, absolutePath))
            {
                return(OSTailoredCode.IsUnixHost && parentPath.TrimEnd('.') == $"{absolutePath}/" ? "." : absolutePath);
            }

            return(OSTailoredCode.IsUnixHost
                                ? absolutePath.Replace(parentPath.TrimEnd('.'), "./")
                                : absolutePath.Replace(parentPath, "."));
#endif
        }
示例#4
0
 /// <exception cref="ArgumentException">running on Windows host, and unmanaged call failed</exception>
 /// <exception cref="FileNotFoundException">running on Windows host, and either path is not a regular file or directory</exception>
 /// <remarks>
 /// always returns a relative path, even if it means going up first<br/>
 /// algorithm for Windows taken from https://stackoverflow.com/a/485516/7467292<br/>
 /// the parameter names seem backwards, but those are the names used in the Win32 API we're calling
 /// </remarks>
 public static string?GetRelativePath(string?fromPath, string?toPath)
 {
     if (fromPath == null || toPath == null)
     {
         return(null);
     }
     if (OSTailoredCode.IsUnixHost)
     {
         var realpathOutput = OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{fromPath}\" \"{toPath}\"", $"invalid path {toPath}, invalid path {fromPath}, or missing realpath binary");
         return(!realpathOutput.StartsWith("../") && realpathOutput != "." && realpathOutput != ".." ? $"./{realpathOutput}" : realpathOutput);
     }
示例#5
0
        /// <remarks>Algorithm for Windows taken from https://stackoverflow.com/a/485516/7467292</remarks>
        public static string GetRelativePath(string fromPath, string toPath)
        {
            if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
            {
                Win32.FileAttributes fromAttr = GetPathAttribute(fromPath);
                Win32.FileAttributes toAttr   = GetPathAttribute(toPath);

                var path = new StringBuilder(260);                 // MAX_PATH
                if (Win32.PathRelativePathTo(
                        path,
                        fromPath,
                        fromAttr,
                        toPath,
                        toAttr) == false)
                {
                    throw new ArgumentException("Paths must have a common prefix");
                }

                return(path.ToString());
            }
#if true
            return(PathManager.IsSubfolder(toPath, fromPath)
                                ? "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{toPath}\" \"{fromPath}\"", $"invalid path {fromPath} or missing realpath binary")
                                : fromPath);
#else // written for Unix port but may be useful for .NET Core
            // algorithm taken from https://stackoverflow.com/a/340454/7467292
            var    dirSepChar = Path.DirectorySeparatorChar;
            string from       = !fromPath.EndsWith(dirSepChar.ToString())
                                ? fromPath + dirSepChar
                                : fromPath;
            string to = !toPath.EndsWith(dirSepChar.ToString())
                                ? toPath + dirSepChar
                                : toPath;

            Uri fromUri = new Uri(from);
            Uri toUri   = new Uri(to);

            if (fromUri.Scheme != toUri.Scheme)
            {
                return(toPath);
            }

            Uri    relativeUri  = fromUri.MakeRelativeUri(toUri);
            string relativePath = Uri.UnescapeDataString(relativeUri.ToString());

            if (string.Equals(toUri.Scheme, Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase))
            {
                relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
            }

            return(relativePath.TrimEnd(dirSepChar));
#endif
        }
示例#6
0
        /// <summary>
        /// Takes an absolute path and attempts to convert it to a relative, based on the system,
        /// or global base if no system is supplied, if it is not a subfolder of the base, it will return the path unaltered
        /// </summary>
        public static string TryMakeRelative(string absolutePath, string system = null)
        {
            var parentPath = string.IsNullOrWhiteSpace(system)
                                ? GetGlobalBasePathAbsolute()
                                : MakeAbsolutePath(GetPlatformBase(system), system);

            if (!IsSubfolder(parentPath, absolutePath))
            {
                return(absolutePath);
            }

            return(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
                                ? absolutePath.Replace(parentPath, ".")
                                : "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{parentPath}\" \"{absolutePath}\"", $"invalid path {absolutePath} or missing realpath binary"));
        }
示例#7
0
        /// <returns><see langword="true"/> iff <paramref name="childPath"/> indicates a child of <paramref name="parentPath"/>, with <see langword="false"/> being returned if either path is <see langword="null"/></returns>
        /// <remarks>algorithm for Windows taken from https://stackoverflow.com/a/7710620/7467292</remarks>
        public static bool IsSubfolderOf(this string?childPath, string?parentPath)
        {
            if (childPath == null || parentPath == null)
            {
                return(false);
            }
            if (childPath == parentPath || childPath.StartsWith($"{parentPath}{Path.DirectorySeparatorChar}"))
            {
                return(true);
            }

            if (OSTailoredCode.IsUnixHost)
            {
#if true
                var c = OSTailoredCode.SimpleSubshell("realpath", $"-Lm \"{childPath}\"", $"invalid path {childPath} or missing realpath binary");
                var p = OSTailoredCode.SimpleSubshell("realpath", $"-Lm \"{parentPath}\"", $"invalid path {parentPath} or missing realpath binary");
                return(c == p || c.StartsWith($"{p}/"));
#else // written for Unix port but may be useful for Windows when moving to .NET Core
                var parentUriPath = new Uri(parentPath.TrimEnd('.')).AbsolutePath.TrimEnd('/');
                try
                {
                    for (var childUri = new DirectoryInfo(childPath).Parent; childUri != null; childUri = childUri.Parent)
                    {
                        if (new Uri(childUri.FullName).AbsolutePath.TrimEnd('/') == parentUriPath)
                        {
                            return(true);
                        }
                    }
                }
                catch
                {
                    // ignored
                }
                return(false);
#endif
            }

            var parentUri = new Uri(parentPath.RemoveSuffix(Path.DirectorySeparatorChar));
            for (var childUri = new DirectoryInfo(childPath); childUri != null; childUri = childUri.Parent)
            {
                if (new Uri(childUri.FullName) == parentUri)
                {
                    return(true);
                }
            }
            return(false);
        }
示例#8
0
        /// <remarks>Algorithm for Windows taken from https://stackoverflow.com/a/7710620/7467292</remarks>
        public static bool IsSubfolder(string parentPath, string childPath)
        {
            if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
            {
                var parentUri = new Uri(parentPath);

                for (var childUri = new DirectoryInfo(childPath).Parent; childUri != null; childUri = childUri?.Parent)
                {
                    if (new Uri(childUri.FullName) == parentUri)
                    {
                        return(true);
                    }
                }

                return(false);
            }

#if true
            return(OSTailoredCode.SimpleSubshell("realpath", $"-L \"{childPath}\"", $"invalid path {childPath} or missing realpath binary")
                   .StartsWith(OSTailoredCode.SimpleSubshell("realpath", $"-L \"{parentPath}\"", $"invalid path {parentPath} or missing realpath binary")));
#else // written for Unix port but may be useful for .NET Core
            {
                var parentUri = new Uri(parentPath.TrimEnd('.'));

                try
                {
                    for (var childUri = new DirectoryInfo(childPath).Parent; childUri != null; childUri = childUri?.Parent)
                    {
                        if (new Uri(childUri.FullName).AbsolutePath.TrimEnd('/') == parentUri.AbsolutePath.TrimEnd('/'))
                        {
                            return(true);
                        }
                    }
                }
                catch
                {
                    // ignored
                }

                return(false);
            }
#endif
        }
示例#9
0
        /// <remarks>Algorithm for Windows taken from https://stackoverflow.com/a/7710620/7467292</remarks>
        private static bool IsSubfolder(string parentPath, string childPath)
        {
            if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
            {
                var parentUri = new Uri(parentPath);

                for (var childUri = new DirectoryInfo(childPath); childUri != null; childUri = childUri?.Parent)
                {
                    if (new Uri(childUri.FullName) == parentUri)
                    {
                        return(true);
                    }
                }

                return(false);
            }

            return(OSTailoredCode.SimpleSubshell("realpath", $"-L \"{childPath}\"", $"invalid path {childPath} or missing realpath binary")
                   .StartsWith(OSTailoredCode.SimpleSubshell("realpath", $"-L \"{parentPath}\"", $"invalid path {parentPath} or missing realpath binary")));
        }
示例#10
0
        /// <returns>the relative path which is equivalent to <paramref name="absolutePath"/> when the CWD is <paramref name="basePath"/>, or <see langword="null"/> if either path is <see langword="null"/></returns>
        /// <remarks>returned string omits trailing slash; implementation calls <see cref="IsSubfolderOf"/> for you</remarks>
        public static string?MakeRelativeTo(this string?absolutePath, string?basePath)
        {
            if (absolutePath == null || basePath == null)
            {
                return(null);
            }
            if (!absolutePath.IsSubfolderOf(basePath))
            {
                return(absolutePath);
            }
            if (!OSTailoredCode.IsUnixHost)
            {
                return(absolutePath.Replace(basePath, ".").RemoveSuffix(Path.DirectorySeparatorChar));
            }
#if true // Unix implementation using realpath
            var realpathOutput = OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{basePath}\" \"{absolutePath}\"", $"invalid path {absolutePath}, invalid path {basePath}, or missing realpath binary");
            return(!realpathOutput.StartsWith("../") && realpathOutput != "." && realpathOutput != ".." ? $"./{realpathOutput}" : realpathOutput);
#else // for some reason there were two Unix implementations in the codebase before me? --yoshi
            // alt. #1
            if (!IsSubfolder(basePath, absolutePath))
            {
                return(OSTailoredCode.IsUnixHost && basePath.TrimEnd('.') == $"{absolutePath}/" ? "." : absolutePath);
            }
            return(OSTailoredCode.IsUnixHost ? absolutePath.Replace(basePath.TrimEnd('.'), "./") : absolutePath.Replace(basePath, "."));

            // alt. #2; algorithm taken from https://stackoverflow.com/a/340454/7467292
            var dirSepChar = Path.DirectorySeparatorChar;
            var fromUri    = new Uri(absolutePath.EndsWith(dirSepChar.ToString()) ? absolutePath : absolutePath + dirSepChar);
            var toUri      = new Uri(basePath.EndsWith(dirSepChar.ToString()) ? basePath : basePath + dirSepChar);
            if (fromUri.Scheme != toUri.Scheme)
            {
                return(basePath);
            }

            var relativePath = Uri.UnescapeDataString(fromUri.MakeRelativeUri(toUri).ToString());
            return((toUri.Scheme.Equals(Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase)
                                ? relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
                                : relativePath
                    ).TrimEnd(dirSepChar));
#endif
        }