diff options
Diffstat (limited to 'src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs')
-rw-r--r-- | src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs b/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs index 01053860..c8582488 100644 --- a/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs +++ b/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Linq; using System.Web.Script.Serialization; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -12,6 +13,13 @@ namespace StardewModdingAPI.ModBuildConfig.Tasks public class CreateModReleaseZip : Task { /********* + ** Properties + *********/ + /// <summary>The name of the manifest file.</summary> + private readonly string ManifestFileName = "manifest.json"; + + + /********* ** Accessors *********/ /// <summary>The mod files to pack.</summary> @@ -30,6 +38,8 @@ namespace StardewModdingAPI.ModBuildConfig.Tasks /********* ** Public methods *********/ + /// <summary>When overridden in a derived class, executes the task.</summary> + /// <returns>true if the task successfully executed; otherwise, false.</returns> public override bool Execute() { try @@ -38,7 +48,7 @@ namespace StardewModdingAPI.ModBuildConfig.Tasks Directory.CreateDirectory(this.OutputFolderPath); // get zip filename - string fileName = string.Format("{0}-{1}.zip", this.ModName, this.GetManifestVersion()); + string fileName = $"{this.ModName}-{this.GetManifestVersion()}.zip"; // clear old zip file if present string zipPath = Path.Combine(this.OutputFolderPath, fileName); @@ -76,28 +86,55 @@ namespace StardewModdingAPI.ModBuildConfig.Tasks } /// <summary>Get a semantic version from the mod manifest (if available).</summary> + /// <exception cref="InvalidOperationException">The manifest file wasn't found or is invalid.</exception> public string GetManifestVersion() { - // Get the file JSON string - string json = ""; - foreach (ITaskItem file in this.Files) + // find manifest file + ITaskItem file = this.Files.FirstOrDefault(p => this.ManifestFileName.Equals(Path.GetFileName(p.ItemSpec), StringComparison.InvariantCultureIgnoreCase)); + if (file == null) + throw new InvalidOperationException($"The mod must include a {this.ManifestFileName} file."); + + // read content + string json = File.ReadAllText(file.ItemSpec); + if (string.IsNullOrWhiteSpace(json)) + throw new InvalidOperationException($"The mod's {this.ManifestFileName} file must not be empty."); + + // parse JSON + IDictionary<string, object> data; + try + { + data = this.Parse(json); + } + catch (Exception ex) { - if (Path.GetFileName(file.ItemSpec).ToLower() != "manifest.json") - continue; - json = File.ReadAllText(file.ItemSpec); - break; + throw new InvalidOperationException($"The mod's {this.ManifestFileName} couldn't be parsed. It doesn't seem to be valid JSON.", ex); } - // Serialize the manifest json into a data object, then get a version object from that. - IDictionary<string, object> data = (IDictionary<string, object>)new JavaScriptSerializer().DeserializeObject(json); - IDictionary<string, object> version = (IDictionary<string, object>)data["Version"]; + // extract version dictionary + IDictionary<string, object> versionFields = (IDictionary<string, object>)data["Version"]; + int major = versionFields.ContainsKey("MajorVersion") ? (int)versionFields["MajorVersion"] : 0; + int minor = versionFields.ContainsKey("MinorVersion") ? (int)versionFields["MinorVersion"] : 0; + int patch = versionFields.ContainsKey("PatchVersion") ? (int)versionFields["PatchVersion"] : 0; - // Store our version numbers for ease of use - int major = (int)version["MajorVersion"]; - int minor = (int)version["MinorVersion"]; - int patch = (int)version["PatchVersion"]; + return $"{major}.{minor}.{patch}"; + } - return String.Format("{0}.{1}.{2}", major, minor, patch); + /// <summary>Get a case-insensitive dictionary matching the given JSON.</summary> + /// <param name="json">The JSON to parse.</param> + private IDictionary<string, object> Parse(string json) + { + IDictionary<string, object> MakeCaseInsensitive(IDictionary<string, object> dict) + { + foreach (var field in dict.ToArray()) + { + if (field.Value is IDictionary<string, object> value) + dict[field.Key] = MakeCaseInsensitive(value); + } + return new Dictionary<string, object>(dict, StringComparer.InvariantCultureIgnoreCase); + } + + IDictionary<string, object> data = (IDictionary<string, object>)new JavaScriptSerializer().DeserializeObject(json); + return MakeCaseInsensitive(data); } } } |