diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-09-08 18:17:09 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-09-08 18:17:09 -0400 |
commit | 5433f9023ed174366c8bf450785aafbdb077d29d (patch) | |
tree | 3a4fc71371d5a1194c2f819444aa7fc32f739830 /src | |
parent | 8a51279ce943ff74b45ec7af308ecf59d73ace9b (diff) | |
parent | d53e033163cfc4a876d6a3341979315a3d937a4f (diff) | |
download | SMAPI-5433f9023ed174366c8bf450785aafbdb077d29d.tar.gz SMAPI-5433f9023ed174366c8bf450785aafbdb077d29d.tar.bz2 SMAPI-5433f9023ed174366c8bf450785aafbdb077d29d.zip |
Merge branch 'develop' into stable
Diffstat (limited to 'src')
-rw-r--r-- | src/SMAPI.Mods.ConsoleCommands/manifest.json | 4 | ||||
-rw-r--r-- | src/SMAPI.Mods.SaveBackup/manifest.json | 4 | ||||
-rw-r--r-- | src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs | 70 | ||||
-rw-r--r-- | src/SMAPI.Tests/Utilities/PathUtilitiesTests.cs | 9 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs | 2 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Utilities/PathUtilities.cs | 41 | ||||
-rw-r--r-- | src/SMAPI/Constants.cs | 2 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetDataForMap.cs | 2 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/ContentCache.cs | 2 | ||||
-rw-r--r-- | src/SMAPI/Framework/ContentPack.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModHelpers/DataHelper.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Utilities/PathUtilities.cs | 6 |
12 files changed, 50 insertions, 100 deletions
diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index c3560466..f15f3c57 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -1,9 +1,9 @@ { "Name": "Console Commands", "Author": "SMAPI", - "Version": "3.7.1", + "Version": "3.7.2", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.7.1" + "MinimumApiVersion": "3.7.2" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index 72e33fd1..c458feed 100644 --- a/src/SMAPI.Mods.SaveBackup/manifest.json +++ b/src/SMAPI.Mods.SaveBackup/manifest.json @@ -1,9 +1,9 @@ { "Name": "Save Backup", "Author": "SMAPI", - "Version": "3.7.1", + "Version": "3.7.2", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.7.1" + "MinimumApiVersion": "3.7.2" } diff --git a/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs b/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs deleted file mode 100644 index 55785bfa..00000000 --- a/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using NUnit.Framework; -using StardewModdingAPI.Toolkit.Utilities; - -namespace SMAPI.Tests.Toolkit -{ - /// <summary>Unit tests for <see cref="PathUtilities"/>.</summary> - [TestFixture] - public class PathUtilitiesTests - { - /********* - ** Unit tests - *********/ - [Test(Description = "Assert that GetSegments returns the expected values.")] - [TestCase("", ExpectedResult = "")] - [TestCase("/", ExpectedResult = "")] - [TestCase("///", ExpectedResult = "")] - [TestCase("/usr/bin", ExpectedResult = "usr|bin")] - [TestCase("/usr//bin//", ExpectedResult = "usr|bin")] - [TestCase("/usr//bin//.././boop.exe", ExpectedResult = "usr|bin|..|.|boop.exe")] - [TestCase(@"C:", ExpectedResult = "C:")] - [TestCase(@"C:/boop", ExpectedResult = "C:|boop")] - [TestCase(@"C:\boop\/usr//bin//.././boop.exe", ExpectedResult = "C:|boop|usr|bin|..|.|boop.exe")] - public string GetSegments(string path) - { - return string.Join("|", PathUtilities.GetSegments(path)); - } - - [Test(Description = "Assert that NormalizePathSeparators returns the expected values.")] -#if SMAPI_FOR_WINDOWS - [TestCase("", ExpectedResult = "")] - [TestCase("/", ExpectedResult = "")] - [TestCase("///", ExpectedResult = "")] - [TestCase("/usr/bin", ExpectedResult = @"usr\bin")] - [TestCase("/usr//bin//", ExpectedResult = @"usr\bin")] - [TestCase("/usr//bin//.././boop.exe", ExpectedResult = @"usr\bin\..\.\boop.exe")] - [TestCase("C:", ExpectedResult = "C:")] - [TestCase("C:/boop", ExpectedResult = @"C:\boop")] - [TestCase(@"C:\usr\bin//.././boop.exe", ExpectedResult = @"C:\usr\bin\..\.\boop.exe")] -#else - [TestCase("", ExpectedResult = "")] - [TestCase("/", ExpectedResult = "/")] - [TestCase("///", ExpectedResult = "/")] - [TestCase("/usr/bin", ExpectedResult = "/usr/bin")] - [TestCase("/usr//bin//", ExpectedResult = "/usr/bin")] - [TestCase("/usr//bin//.././boop.exe", ExpectedResult = "/usr/bin/.././boop.exe")] - [TestCase("C:", ExpectedResult = "C:")] - [TestCase("C:/boop", ExpectedResult = "C:/boop")] - [TestCase(@"C:\usr\bin//.././boop.exe", ExpectedResult = "C:/usr/bin/.././boop.exe")] -#endif - public string NormalizePathSeparators(string path) - { - return PathUtilities.NormalizePathSeparators(path); - } - - [Test(Description = "Assert that GetRelativePath returns the expected values.")] -#if SMAPI_FOR_WINDOWS - [TestCase(@"C:\", @"C:\", ExpectedResult = "./")] - [TestCase(@"C:\grandparent\parent\child", @"C:\grandparent\parent\sibling", ExpectedResult = @"..\sibling")] - [TestCase(@"C:\grandparent\parent\child", @"C:\cousin\file.exe", ExpectedResult = @"..\..\..\cousin\file.exe")] -#else - [TestCase("/", "/", ExpectedResult = "./")] - [TestCase("/grandparent/parent/child", "/grandparent/parent/sibling", ExpectedResult = "../sibling")] - [TestCase("/grandparent/parent/child", "/cousin/file.exe", ExpectedResult = "../../../cousin/file.exe")] -#endif - public string GetRelativePath(string sourceDir, string targetPath) - { - return PathUtilities.GetRelativePath(sourceDir, targetPath); - } - } -} diff --git a/src/SMAPI.Tests/Utilities/PathUtilitiesTests.cs b/src/SMAPI.Tests/Utilities/PathUtilitiesTests.cs index ea69a9ea..b5494003 100644 --- a/src/SMAPI.Tests/Utilities/PathUtilitiesTests.cs +++ b/src/SMAPI.Tests/Utilities/PathUtilitiesTests.cs @@ -179,10 +179,10 @@ namespace SMAPI.Tests.Utilities ****/ [Test(Description = "Assert that PathUtilities.NormalizePathSeparators normalizes paths correctly.")] [TestCaseSource(nameof(PathUtilitiesTests.SamplePaths))] - public void NormalizePathSeparators(SamplePath path) + public void NormalizePath(SamplePath path) { // act - string normalized = PathUtilities.NormalizePathSeparators(path.OriginalPath); + string normalized = PathUtilities.NormalizePath(path.OriginalPath); // assert #if SMAPI_FOR_WINDOWS @@ -218,11 +218,6 @@ namespace SMAPI.Tests.Utilities ExpectedResult = @"path\to\child" )] [TestCase( - @"\\parent\unc", - @"\\adjacent\unc", - ExpectedResult = @"\\adjacent\unc" - )] - [TestCase( @"C:\same\path", @"C:\same\path", ExpectedResult = @"." diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index 450d600a..825988a5 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -29,7 +29,7 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning IEnumerable<string> paths = this .GetCustomInstallPaths(platform) .Concat(this.GetDefaultInstallPaths(platform)) - .Select(PathUtilities.NormalizePathSeparators) + .Select(PathUtilities.NormalizePath) .Distinct(StringComparer.OrdinalIgnoreCase); // yield valid folders diff --git a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs index bd5fafbc..c9fb6213 100644 --- a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs +++ b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs @@ -23,7 +23,7 @@ namespace StardewModdingAPI.Toolkit.Utilities public static readonly char[] PossiblePathSeparators = new[] { '/', '\\', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.Distinct().ToArray(); /// <summary>The preferred directory separator character in an asset key.</summary> - public static readonly string PreferredPathSeparator = Path.DirectorySeparatorChar.ToString(); + public static readonly char PreferredPathSeparator = Path.DirectorySeparatorChar; /********* @@ -40,15 +40,37 @@ namespace StardewModdingAPI.Toolkit.Utilities : path.Split(PathUtilities.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries); } - /// <summary>Normalize path separators in a file path.</summary> + /// <summary>Normalize separators in a file path.</summary> /// <param name="path">The file path to normalize.</param> [Pure] - public static string NormalizePathSeparators(string path) + public static string NormalizePath(string path) { - if (string.IsNullOrWhiteSpace(path)) + path = path?.Trim(); + if (string.IsNullOrEmpty(path)) return path; - return string.Join(PathUtilities.PreferredPathSeparator, path.Split(PathUtilities.PossiblePathSeparators)); + // get basic path format (e.g. /some/asset\\path/ => some\asset\path) + string[] segments = PathUtilities.GetSegments(path); + string newPath = string.Join(PathUtilities.PreferredPathSeparator.ToString(), segments); + + // keep root prefix + bool hasRoot = false; + if (path.StartsWith(PathUtilities.WindowsUncRoot)) + { + newPath = PathUtilities.WindowsUncRoot + newPath; + hasRoot = true; + } + else if (PathUtilities.PossiblePathSeparators.Contains(path[0])) + { + newPath = PathUtilities.PreferredPathSeparator + newPath; + hasRoot = true; + } + + // keep trailing separator + if ((!hasRoot || segments.Any()) && PathUtilities.PossiblePathSeparators.Contains(path[path.Length - 1])) + newPath += PathUtilities.PreferredPathSeparator; + + return newPath; } /// <summary>Get a directory or file path relative to a given source path. If no relative path is possible (e.g. the paths are on different drives), an absolute path is returned.</summary> @@ -69,7 +91,10 @@ namespace StardewModdingAPI.Toolkit.Utilities throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{sourceDir}'."); // get relative path - string relative = PathUtilities.NormalizePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString())); + string rawUrl = Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()); + if (rawUrl.StartsWith("file://")) + rawUrl = PathUtilities.WindowsUncRoot + rawUrl.Substring("file://".Length); + string relative = PathUtilities.NormalizePath(rawUrl); // normalize if (relative == "") @@ -77,8 +102,8 @@ namespace StardewModdingAPI.Toolkit.Utilities else { // trim trailing slash from URL - if (relative.EndsWith(PathUtilities.PreferredPathSeparator)) - relative = relative.Substring(0, relative.Length - PathUtilities.PreferredPathSeparator.Length); + if (relative.EndsWith(PathUtilities.PreferredPathSeparator.ToString())) + relative = relative.Substring(0, relative.Length - 1); // fix root if (relative.StartsWith("file:") && !targetPath.Contains("file:")) diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 7540061d..6017a1d4 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -51,7 +51,7 @@ namespace StardewModdingAPI ** Public ****/ /// <summary>SMAPI's current semantic version.</summary> - public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.7.1"); + public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.7.2"); /// <summary>The minimum supported version of Stardew Valley.</summary> public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.1"); diff --git a/src/SMAPI/Framework/Content/AssetDataForMap.cs b/src/SMAPI/Framework/Content/AssetDataForMap.cs index e80c6e53..20f0ed0f 100644 --- a/src/SMAPI/Framework/Content/AssetDataForMap.cs +++ b/src/SMAPI/Framework/Content/AssetDataForMap.cs @@ -153,7 +153,7 @@ namespace StardewModdingAPI.Framework.Content if (string.IsNullOrWhiteSpace(path)) return string.Empty; - path = PathUtilities.NormalizePathSeparators(path.Trim()); + path = PathUtilities.NormalizePath(path); if (path.StartsWith($"Maps{PathUtilities.PreferredPathSeparator}", StringComparison.OrdinalIgnoreCase)) path = path.Substring($"Maps{PathUtilities.PreferredPathSeparator}".Length); if (path.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) diff --git a/src/SMAPI/Framework/Content/ContentCache.cs b/src/SMAPI/Framework/Content/ContentCache.cs index 2052f6bf..af65e07e 100644 --- a/src/SMAPI/Framework/Content/ContentCache.cs +++ b/src/SMAPI/Framework/Content/ContentCache.cs @@ -80,7 +80,7 @@ namespace StardewModdingAPI.Framework.Content [Pure] public string NormalizePathSeparators(string path) { - return PathUtilities.NormalizePathSeparators(path); + return PathUtilities.NormalizePath(path); } /// <summary>Normalize a cache key so it's consistent with the underlying cache.</summary> diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs index 55c1a0b2..65abba5b 100644 --- a/src/SMAPI/Framework/ContentPack.cs +++ b/src/SMAPI/Framework/ContentPack.cs @@ -62,7 +62,7 @@ namespace StardewModdingAPI.Framework { this.AssertRelativePath(path, nameof(this.ReadJsonFile)); - path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path)); + path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePath(path)); return this.JsonHelper.ReadJsonFileIfExists(path, out TModel model) ? model : null; @@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework { this.AssertRelativePath(path, nameof(this.WriteJsonFile)); - path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path)); + path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePath(path)); this.JsonHelper.WriteJsonFile(path, data); } diff --git a/src/SMAPI/Framework/ModHelpers/DataHelper.cs b/src/SMAPI/Framework/ModHelpers/DataHelper.cs index c232a6dd..41612387 100644 --- a/src/SMAPI/Framework/ModHelpers/DataHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/DataHelper.cs @@ -45,7 +45,7 @@ namespace StardewModdingAPI.Framework.ModHelpers if (!PathUtilities.IsSafeRelativePath(path)) throw new InvalidOperationException($"You must call {nameof(IModHelper.Data)}.{nameof(this.ReadJsonFile)} with a relative path."); - path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePathSeparators(path)); + path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePath(path)); return this.JsonHelper.ReadJsonFileIfExists(path, out TModel data) ? data : null; @@ -57,7 +57,7 @@ namespace StardewModdingAPI.Framework.ModHelpers if (!PathUtilities.IsSafeRelativePath(path)) throw new InvalidOperationException($"You must call {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteJsonFile)} with a relative path (without directory climbing)."); - path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePathSeparators(path)); + path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePath(path)); this.JsonHelper.WriteJsonFile(path, data); } diff --git a/src/SMAPI/Utilities/PathUtilities.cs b/src/SMAPI/Utilities/PathUtilities.cs index ea134468..19f16ea9 100644 --- a/src/SMAPI/Utilities/PathUtilities.cs +++ b/src/SMAPI/Utilities/PathUtilities.cs @@ -18,12 +18,12 @@ namespace StardewModdingAPI.Utilities return ToolkitPathUtilities.GetSegments(path, limit); } - /// <summary>Normalize path separators in a file path.</summary> + /// <summary>Normalize separators in a file path.</summary> /// <param name="path">The file path to normalize.</param> [Pure] - public static string NormalizePathSeparators(string path) + public static string NormalizePath(string path) { - return ToolkitPathUtilities.NormalizePathSeparators(path); + return ToolkitPathUtilities.NormalizePath(path); } /// <summary>Get whether a path is relative and doesn't try to climb out of its containing folder (e.g. doesn't contain <c>../</c>).</summary> |