summaryrefslogtreecommitdiff
path: root/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2017-10-08 02:03:55 -0400
committerJesse Plamondon-Willard <github@jplamondonw.com>2017-10-08 02:03:55 -0400
commite2e7e096b7f62eb6a5145970ecac3b7edc0bfef1 (patch)
tree2e9c4efe81f205f1178c5c5908a8b5f390e400ab /src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs
parentddad601de3610a56a87c3f943d7ecc9c92af15f9 (diff)
downloadSMAPI-e2e7e096b7f62eb6a5145970ecac3b7edc0bfef1.tar.gz
SMAPI-e2e7e096b7f62eb6a5145970ecac3b7edc0bfef1.tar.bz2
SMAPI-e2e7e096b7f62eb6a5145970ecac3b7edc0bfef1.zip
handle various edge cases in manifest parsing for zip filename
Diffstat (limited to 'src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs')
-rw-r--r--src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs69
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);
}
}
}