From f5807e22be157d908e3b8c65f19acaa16c3588e7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 16 Sep 2021 22:47:05 -0400 Subject: add BundleExtraAssemblies package option for new .NET 5 reference model --- .../Framework/ExtraAssemblyType.cs | 21 ++++ .../Framework/ModFileManager.cs | 124 ++++++++++++++++----- 2 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 src/SMAPI.ModBuildConfig/Framework/ExtraAssemblyType.cs (limited to 'src/SMAPI.ModBuildConfig/Framework') diff --git a/src/SMAPI.ModBuildConfig/Framework/ExtraAssemblyType.cs b/src/SMAPI.ModBuildConfig/Framework/ExtraAssemblyType.cs new file mode 100644 index 00000000..571bf7c7 --- /dev/null +++ b/src/SMAPI.ModBuildConfig/Framework/ExtraAssemblyType.cs @@ -0,0 +1,21 @@ +using System; + +namespace StardewModdingAPI.ModBuildConfig.Framework +{ + /// An extra assembly type for the field. + [Flags] + internal enum ExtraAssemblyTypes + { + /// Don't include extra assemblies. + None = 0, + + /// Assembly files which are part of MonoGame, SMAPI, or Stardew Valley. + Game = 1, + + /// Assembly files whose names start with Microsoft.* or System.*. + System = 2, + + /// Assembly files which don't match any other category. + ThirdParty = 4 + } +} diff --git a/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs b/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs index fbb91193..ad4ffdf9 100644 --- a/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs +++ b/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs @@ -21,6 +21,45 @@ namespace StardewModdingAPI.ModBuildConfig.Framework /// The files that are part of the package. private readonly IDictionary Files; + /// The file extensions used by assembly files. + private readonly ISet AssemblyFileExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) + { + ".dll", + ".exe", + ".pdb", + ".xml" + }; + + /// The DLLs which match the type. + private readonly ISet GameDllNames = new HashSet + { + // SMAPI + "0Harmony", + "Mono.Cecil", + "Mono.Cecil.Mdb", + "Mono.Cecil.Pdb", + "MonoMod.Common", + "Newtonsoft.Json", + "StardewModdingAPI", + "SMAPI.Toolkit", + "SMAPI.Toolkit.CoreInterfaces", + "TMXTile", + + // game + framework + "BmFont", + "FAudio-CS", + "GalaxyCSharp", + "GalaxyCSharpGlue", + "Lidgren.Network", + "MonoGame.Framework", + "SkiaSharp", + "Stardew Valley", + "StardewValley.GameData", + "Steamworks.NET", + "TextCopy", + "xTile" + }; + /********* ** Public methods @@ -30,9 +69,11 @@ namespace StardewModdingAPI.ModBuildConfig.Framework /// The folder containing the build output. /// The custom relative file paths provided by the user to ignore. /// Custom regex patterns matching files to ignore when deploying or zipping the mod. + /// The extra assembly types which should be bundled with the mod. + /// The name (without extension or path) for the current mod's DLL. /// Whether to validate that required mod files like the manifest are present. /// The mod package isn't valid. - public ModFileManager(string projectDir, string targetDir, string[] ignoreFilePaths, Regex[] ignoreFilePatterns, bool validateRequiredModFiles) + public ModFileManager(string projectDir, string targetDir, string[] ignoreFilePaths, Regex[] ignoreFilePatterns, ExtraAssemblyTypes bundleAssemblyTypes, string modDllName, bool validateRequiredModFiles) { this.Files = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -48,7 +89,7 @@ namespace StardewModdingAPI.ModBuildConfig.Framework string relativePath = entry.Item1; FileInfo file = entry.Item2; - if (!this.ShouldIgnore(file, relativePath, ignoreFilePaths, ignoreFilePatterns)) + if (!this.ShouldIgnore(file, relativePath, ignoreFilePaths, ignoreFilePatterns, bundleAssemblyTypes, modDllName)) this.Files[relativePath] = file; } @@ -152,39 +193,70 @@ namespace StardewModdingAPI.ModBuildConfig.Framework /// The file's relative path in the package. /// The custom relative file paths provided by the user to ignore. /// Custom regex patterns matching files to ignore when deploying or zipping the mod. - private bool ShouldIgnore(FileInfo file, string relativePath, string[] ignoreFilePaths, Regex[] ignoreFilePatterns) + /// The extra assembly types which should be bundled with the mod. + /// The name (without extension or path) for the current mod's DLL. + private bool ShouldIgnore(FileInfo file, string relativePath, string[] ignoreFilePaths, Regex[] ignoreFilePatterns, ExtraAssemblyTypes bundleAssemblyTypes, string modDllName) { - bool IsAssemblyFile(string baseName) + // apply custom patterns + if (ignoreFilePaths.Any(p => p == relativePath) || ignoreFilePatterns.Any(p => p.IsMatch(relativePath))) + return true; + + // ignore unneeded files + { + bool shouldIgnore = + // release zips + this.EqualsInvariant(file.Extension, ".zip") + + // *.deps.json (only SMAPI's top-level one is used) + || file.Name.EndsWith(".deps.json") + + // code analysis files + || file.Name.EndsWith(".CodeAnalysisLog.xml", StringComparison.OrdinalIgnoreCase) + || file.Name.EndsWith(".lastcodeanalysissucceeded", StringComparison.OrdinalIgnoreCase) + + // translation class builder (not used at runtime) + || ( + file.Name.StartsWith("Pathoschild.Stardew.ModTranslationClassBuilder") + && this.AssemblyFileExtensions.Contains(file.Extension) + ) + + // OS metadata files + || this.EqualsInvariant(file.Name, ".DS_Store") + || this.EqualsInvariant(file.Name, "Thumbs.db"); + if (shouldIgnore) + return true; + } + + // check for bundled assembly types + // When bundleAssemblyTypes is set, *all* dependencies are copied into the build output but only those which match the given assembly types should be bundled. + if (bundleAssemblyTypes != ExtraAssemblyTypes.None) { - return - this.EqualsInvariant(file.Name, $"{baseName}.dll") - || this.EqualsInvariant(file.Name, $"{baseName}.pdb") - || this.EqualsInvariant(file.Name, $"{baseName}.xnb"); + var type = this.GetExtraAssemblyType(file, modDllName); + if (type != ExtraAssemblyTypes.None && !bundleAssemblyTypes.HasFlag(type)) + return true; } - return - // release zips - this.EqualsInvariant(file.Extension, ".zip") + return false; + } - // unneeded *.deps.json (only SMAPI's top-level one is used) - || file.Name.EndsWith(".deps.json") + /// Get the extra assembly type for a file, assuming that the user specified one or more extra types to bundle. + /// The file to check. + /// The name (without extension or path) for the current mod's DLL. + private ExtraAssemblyTypes GetExtraAssemblyType(FileInfo file, string modDllName) + { + string baseName = Path.GetFileNameWithoutExtension(file.Name); + string extension = file.Extension; - // dependencies bundled with SMAPI - || IsAssemblyFile("0Harmony") - || IsAssemblyFile("Newtonsoft.Json") - || IsAssemblyFile("Pathoschild.Stardew.ModTranslationClassBuilder") // not used at runtime + if (baseName == modDllName || !this.AssemblyFileExtensions.Contains(extension)) + return ExtraAssemblyTypes.None; - // code analysis files - || file.Name.EndsWith(".CodeAnalysisLog.xml", StringComparison.OrdinalIgnoreCase) - || file.Name.EndsWith(".lastcodeanalysissucceeded", StringComparison.OrdinalIgnoreCase) + if (this.GameDllNames.Contains(baseName)) + return ExtraAssemblyTypes.Game; - // OS metadata files - || this.EqualsInvariant(file.Name, ".DS_Store") - || this.EqualsInvariant(file.Name, "Thumbs.db") + if (baseName.StartsWith("System.", StringComparison.OrdinalIgnoreCase) || baseName.StartsWith("Microsoft.", StringComparison.OrdinalIgnoreCase)) + return ExtraAssemblyTypes.System; - // custom ignore patterns - || ignoreFilePaths.Any(p => p == relativePath) - || ignoreFilePatterns.Any(p => p.IsMatch(relativePath)); + return ExtraAssemblyTypes.ThirdParty; } /// Get whether a string is equal to another case-insensitively. -- cgit