From abe52deba7e2b8081babd69785f902c7f7a52100 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 8 Oct 2017 14:50:04 -0400 Subject: rename build task for broader use --- src/SMAPI.ModBuildConfig/DeployModTask.cs | 153 +++++++++++++++++++++ .../StardewModdingAPI.ModBuildConfig.csproj | 2 +- .../Tasks/CreateModReleaseZip.cs | 153 --------------------- src/SMAPI.ModBuildConfig/build/smapi.targets | 4 +- 4 files changed, 156 insertions(+), 156 deletions(-) create mode 100644 src/SMAPI.ModBuildConfig/DeployModTask.cs delete mode 100644 src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs (limited to 'src') diff --git a/src/SMAPI.ModBuildConfig/DeployModTask.cs b/src/SMAPI.ModBuildConfig/DeployModTask.cs new file mode 100644 index 00000000..0483f651 --- /dev/null +++ b/src/SMAPI.ModBuildConfig/DeployModTask.cs @@ -0,0 +1,153 @@ +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; +using StardewModdingAPI.Common; + +namespace StardewModdingAPI.ModBuildConfig +{ + /// A build task which deploys the mod files and prepares a release zip. + public class DeployModTask : Task + { + /********* + ** Properties + *********/ + /// The name of the manifest file. + private readonly string ManifestFileName = "manifest.json"; + + + /********* + ** Accessors + *********/ + /// The mod files to pack. + [Required] + public ITaskItem[] Files { get; set; } + + /// The name of the mod. + [Required] + public string ModName { get; set; } + + /// The absolute or relative path to the folder which should contain the generated zip file. + [Required] + public string OutputFolderPath { get; set; } + + + /********* + ** Public methods + *********/ + /// When overridden in a derived class, executes the task. + /// true if the task successfully executed; otherwise, false. + public override bool Execute() + { + try + { + // get names + string zipName = this.EscapeInvalidFilenameCharacters($"{this.ModName}-{this.GetManifestVersion()}.zip"); + string folderName = this.EscapeInvalidFilenameCharacters(this.ModName); + string zipPath = Path.Combine(this.OutputFolderPath, zipName); + + // create zip file + Directory.CreateDirectory(this.OutputFolderPath); + using (Stream zipStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write)) + using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)) + { + foreach (ITaskItem file in this.Files) + { + // get file info + string filePath = file.ItemSpec; + string entryName = folderName + '/' + file.GetMetadata("RecursiveDir") + file.GetMetadata("Filename") + file.GetMetadata("Extension"); + if (new FileInfo(filePath).Directory.Name.Equals("i18n", StringComparison.InvariantCultureIgnoreCase)) + entryName = Path.Combine("i18n", entryName); + + // add to zip + using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + using (Stream fileStreamInZip = archive.CreateEntry(entryName).Open()) + { + fileStream.CopyTo(fileStreamInZip); + } + } + } + + return true; + } + catch (Exception ex) + { + this.Log.LogErrorFromException(ex); + return false; + } + } + + /// Get a semantic version from the mod manifest (if available). + /// The manifest file wasn't found or is invalid. + public string GetManifestVersion() + { + // 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 data; + try + { + data = this.Parse(json); + } + catch (Exception ex) + { + throw new InvalidOperationException($"The mod's {this.ManifestFileName} couldn't be parsed. It doesn't seem to be valid JSON.", ex); + } + + // get version field + object versionObj = data.ContainsKey("Version") ? data["Version"] : null; + if (versionObj == null) + throw new InvalidOperationException($"The mod's {this.ManifestFileName} must have a version field."); + + // get version string + if (versionObj is IDictionary versionFields) // SMAPI 1.x + { + 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; + string tag = versionFields.ContainsKey("Build") ? (string) versionFields["Build"] : null; + return new SemanticVersionImpl(major, minor, patch, tag).ToString(); + } + return new SemanticVersionImpl(versionObj.ToString()).ToString(); // SMAPI 2.0+ + } + + /// Get a case-insensitive dictionary matching the given JSON. + /// The JSON to parse. + private IDictionary Parse(string json) + { + IDictionary MakeCaseInsensitive(IDictionary dict) + { + foreach (var field in dict.ToArray()) + { + if (field.Value is IDictionary value) + dict[field.Key] = MakeCaseInsensitive(value); + } + return new Dictionary(dict, StringComparer.InvariantCultureIgnoreCase); + } + + IDictionary data = (IDictionary)new JavaScriptSerializer().DeserializeObject(json); + return MakeCaseInsensitive(data); + } + + /// Get a copy of a filename with all invalid filename characters substituted. + /// The filename. + private string EscapeInvalidFilenameCharacters(string name) + { + foreach (char invalidChar in Path.GetInvalidFileNameChars()) + name = name.Replace(invalidChar, '.'); + return name; + } + } +} diff --git a/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj b/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj index 3ca3cca8..f943bc97 100644 --- a/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj +++ b/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj @@ -38,7 +38,7 @@ - + diff --git a/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs b/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs deleted file mode 100644 index b9460b39..00000000 --- a/src/SMAPI.ModBuildConfig/Tasks/CreateModReleaseZip.cs +++ /dev/null @@ -1,153 +0,0 @@ -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; -using StardewModdingAPI.Common; - -namespace StardewModdingAPI.ModBuildConfig.Tasks -{ - /// A build task which packs mod files into a conventional release zip. - public class CreateModReleaseZip : Task - { - /********* - ** Properties - *********/ - /// The name of the manifest file. - private readonly string ManifestFileName = "manifest.json"; - - - /********* - ** Accessors - *********/ - /// The mod files to pack. - [Required] - public ITaskItem[] Files { get; set; } - - /// The name of the mod. - [Required] - public string ModName { get; set; } - - /// The absolute or relative path to the folder which should contain the generated zip file. - [Required] - public string OutputFolderPath { get; set; } - - - /********* - ** Public methods - *********/ - /// When overridden in a derived class, executes the task. - /// true if the task successfully executed; otherwise, false. - public override bool Execute() - { - try - { - // get names - string zipName = this.EscapeInvalidFilenameCharacters($"{this.ModName}-{this.GetManifestVersion()}.zip"); - string folderName = this.EscapeInvalidFilenameCharacters(this.ModName); - string zipPath = Path.Combine(this.OutputFolderPath, zipName); - - // create zip file - Directory.CreateDirectory(this.OutputFolderPath); - using (Stream zipStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write)) - using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)) - { - foreach (ITaskItem file in this.Files) - { - // get file info - string filePath = file.ItemSpec; - string entryName = folderName + '/' + file.GetMetadata("RecursiveDir") + file.GetMetadata("Filename") + file.GetMetadata("Extension"); - if (new FileInfo(filePath).Directory.Name.Equals("i18n", StringComparison.InvariantCultureIgnoreCase)) - entryName = Path.Combine("i18n", entryName); - - // add to zip - using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) - using (Stream fileStreamInZip = archive.CreateEntry(entryName).Open()) - { - fileStream.CopyTo(fileStreamInZip); - } - } - } - - return true; - } - catch (Exception ex) - { - this.Log.LogErrorFromException(ex); - return false; - } - } - - /// Get a semantic version from the mod manifest (if available). - /// The manifest file wasn't found or is invalid. - public string GetManifestVersion() - { - // 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 data; - try - { - data = this.Parse(json); - } - catch (Exception ex) - { - throw new InvalidOperationException($"The mod's {this.ManifestFileName} couldn't be parsed. It doesn't seem to be valid JSON.", ex); - } - - // get version field - object versionObj = data.ContainsKey("Version") ? data["Version"] : null; - if (versionObj == null) - throw new InvalidOperationException($"The mod's {this.ManifestFileName} must have a version field."); - - // get version string - if (versionObj is IDictionary versionFields) // SMAPI 1.x - { - 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; - string tag = versionFields.ContainsKey("Build") ? (string) versionFields["Build"] : null; - return new SemanticVersionImpl(major, minor, patch, tag).ToString(); - } - return new SemanticVersionImpl(versionObj.ToString()).ToString(); // SMAPI 2.0+ - } - - /// Get a case-insensitive dictionary matching the given JSON. - /// The JSON to parse. - private IDictionary Parse(string json) - { - IDictionary MakeCaseInsensitive(IDictionary dict) - { - foreach (var field in dict.ToArray()) - { - if (field.Value is IDictionary value) - dict[field.Key] = MakeCaseInsensitive(value); - } - return new Dictionary(dict, StringComparer.InvariantCultureIgnoreCase); - } - - IDictionary data = (IDictionary)new JavaScriptSerializer().DeserializeObject(json); - return MakeCaseInsensitive(data); - } - - /// Get a copy of a filename with all invalid filename characters substituted. - /// The filename. - private string EscapeInvalidFilenameCharacters(string name) - { - foreach (char invalidChar in Path.GetInvalidFileNameChars()) - name = name.Replace(invalidChar, '.'); - return name; - } - } -} diff --git a/src/SMAPI.ModBuildConfig/build/smapi.targets b/src/SMAPI.ModBuildConfig/build/smapi.targets index b4bc8d8b..61bf96ac 100644 --- a/src/SMAPI.ModBuildConfig/build/smapi.targets +++ b/src/SMAPI.ModBuildConfig/build/smapi.targets @@ -2,7 +2,7 @@ - + - + -- cgit