From 889004f1eba31aa3a5069e1dcbe79896d05720b0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 19 Apr 2022 19:03:47 -0400 Subject: move deprecation code into namespace --- src/SMAPI/Constants.cs | 1 + src/SMAPI/Framework/Content/AssetInfo.cs | 1 + .../ContentManagers/GameContentManager.cs | 1 + src/SMAPI/Framework/DeprecationLevel.cs | 15 -- src/SMAPI/Framework/DeprecationManager.cs | 171 --------------------- src/SMAPI/Framework/DeprecationWarning.cs | 48 ------ .../Framework/Deprecations/DeprecationLevel.cs | 15 ++ .../Framework/Deprecations/DeprecationManager.cs | 171 +++++++++++++++++++++ .../Framework/Deprecations/DeprecationWarning.cs | 48 ++++++ src/SMAPI/Framework/ModHelpers/CommandHelper.cs | 1 + src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 1 + src/SMAPI/Framework/ModHelpers/ModHelper.cs | 1 + src/SMAPI/Framework/SCore.cs | 1 + src/SMAPI/Utilities/PerScreen.cs | 1 + 14 files changed, 242 insertions(+), 234 deletions(-) delete mode 100644 src/SMAPI/Framework/DeprecationLevel.cs delete mode 100644 src/SMAPI/Framework/DeprecationManager.cs delete mode 100644 src/SMAPI/Framework/DeprecationWarning.cs create mode 100644 src/SMAPI/Framework/Deprecations/DeprecationLevel.cs create mode 100644 src/SMAPI/Framework/Deprecations/DeprecationManager.cs create mode 100644 src/SMAPI/Framework/Deprecations/DeprecationWarning.cs diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index d40b97f4..ddb08435 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -6,6 +6,7 @@ using System.Reflection; using Mono.Cecil; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework; +using StardewModdingAPI.Framework.Deprecations; using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Toolkit.Framework; using StardewModdingAPI.Toolkit.Utilities; diff --git a/src/SMAPI/Framework/Content/AssetInfo.cs b/src/SMAPI/Framework/Content/AssetInfo.cs index 16b71487..c632249d 100644 --- a/src/SMAPI/Framework/Content/AssetInfo.cs +++ b/src/SMAPI/Framework/Content/AssetInfo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI.Framework.Deprecations; namespace StardewModdingAPI.Framework.Content { diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 6469fea4..083df454 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -8,6 +8,7 @@ using System.Reflection; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Content; +using StardewModdingAPI.Framework.Deprecations; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Utilities; using StardewModdingAPI.Internal; diff --git a/src/SMAPI/Framework/DeprecationLevel.cs b/src/SMAPI/Framework/DeprecationLevel.cs deleted file mode 100644 index 12b50952..00000000 --- a/src/SMAPI/Framework/DeprecationLevel.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace StardewModdingAPI.Framework -{ - /// Indicates how deprecated something is. - internal enum DeprecationLevel - { - /// It's deprecated but won't be removed soon. Mod authors have some time to update their mods. Deprecation warnings should be logged, but not written to the console. - Notice, - - /// Mods should no longer be using it. Deprecation messages should be debug entries in the console. - Info, - - /// The code will be removed soon. Deprecation messages should be warnings in the console. - PendingRemoval - } -} diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs deleted file mode 100644 index 37a5c8ef..00000000 --- a/src/SMAPI/Framework/DeprecationManager.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; - -namespace StardewModdingAPI.Framework -{ - /// Manages deprecation warnings. - internal class DeprecationManager - { - /********* - ** Fields - *********/ - /// The deprecations which have already been logged (as 'mod name::noun phrase::version'). - private readonly HashSet LoggedDeprecations = new(StringComparer.OrdinalIgnoreCase); - - /// Encapsulates monitoring and logging for a given module. - private readonly IMonitor Monitor; - - /// Tracks the installed mods. - private readonly ModRegistry ModRegistry; - - /// The queued deprecation warnings to display. - private readonly IList QueuedWarnings = new List(); - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// Encapsulates monitoring and logging for a given module. - /// Tracks the installed mods. - public DeprecationManager(IMonitor monitor, ModRegistry modRegistry) - { - this.Monitor = monitor; - this.ModRegistry = modRegistry; - } - - /// Get a mod for the closest assembly registered as a source of deprecation warnings. - /// Returns the source name, or null if no registered assemblies were found. - public IModMetadata? GetModFromStack() - { - return this.ModRegistry.GetFromStack(); - } - - /// Get a mod from its unique ID. - /// The mod's unique ID. - public IModMetadata? GetMod(string modId) - { - return this.ModRegistry.Get(modId); - } - - /// Log a deprecation warning. - /// The mod which used the deprecated code, if known. - /// A noun phrase describing what is deprecated. - /// The SMAPI version which deprecated it. - /// How deprecated the code is. - public void Warn(IModMetadata? source, string nounPhrase, string version, DeprecationLevel severity) - { - // ignore if already warned - if (!this.MarkWarned(source, nounPhrase, version)) - return; - - // queue warning - var stack = new StackTrace(skipFrames: 1); // skip this method - this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity, stack)); - } - - /// A placeholder method used to track deprecated code for which a separate warning will be shown. - /// The SMAPI version which deprecated it. - /// How deprecated the code is. - public void PlaceholderWarn(string version, DeprecationLevel severity) { } - - /// Print any queued messages. - public void PrintQueued() - { - foreach (DeprecationWarning warning in this.QueuedWarnings.OrderBy(p => p.ModName).ThenBy(p => p.NounPhrase)) - { - // build message - string message = $"{warning.ModName} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version})."; - - // get log level - LogLevel level; - switch (warning.Level) - { - case DeprecationLevel.Notice: - level = LogLevel.Trace; - break; - - case DeprecationLevel.Info: - level = LogLevel.Debug; - break; - - case DeprecationLevel.PendingRemoval: - level = LogLevel.Warn; - break; - - default: - throw new NotSupportedException($"Unknown deprecation level '{warning.Level}'."); - } - - // log message - if (level == LogLevel.Trace) - this.Monitor.Log($"{message}\n{this.GetSimplifiedStackTrace(warning.StackTrace, warning.Mod)}", level); - else - { - this.Monitor.Log(message, level); - this.Monitor.Log(this.GetSimplifiedStackTrace(warning.StackTrace, warning.Mod), LogLevel.Debug); - } - } - - this.QueuedWarnings.Clear(); - } - - - /********* - ** Private methods - *********/ - /// Mark a deprecation warning as already logged. - /// The mod which used the deprecated code. - /// A noun phrase describing what is deprecated (e.g. "the Extensions.AsInt32 method"). - /// The SMAPI version which deprecated it. - /// Returns whether the deprecation was successfully marked as warned. Returns false if it was already marked. - private bool MarkWarned(IModMetadata? source, string nounPhrase, string version) - { - string key = $"{source?.DisplayName ?? ""}::{nounPhrase}::{version}"; - if (this.LoggedDeprecations.Contains(key)) - return false; - this.LoggedDeprecations.Add(key); - return true; - } - - /// Get the simplest stack trace which shows where in the mod the deprecated code was called from. - /// The stack trace. - /// The mod for which to show a stack trace. - private string GetSimplifiedStackTrace(StackTrace stack, IModMetadata? mod) - { - // unknown mod, show entire stack trace - if (mod == null) - return stack.ToString(); - - // get frame info - var frames = stack - .GetFrames() - .Select(frame => (Frame: frame, Mod: this.ModRegistry.GetFrom(frame))) - .ToArray(); - var modIds = new HashSet( - from frame in frames - let id = frame.Mod?.Manifest.UniqueID - where id != null - select id - ); - - // can't filter to the target mod - if (modIds.Count != 1 || !modIds.Contains(mod.Manifest.UniqueID)) - return stack.ToString(); - - // get stack frames for the target mod, plus one for context - var framesStartingAtMod = frames.SkipWhile(p => p.Mod == null).ToArray(); - var displayFrames = framesStartingAtMod.TakeWhile(p => p.Mod != null).ToArray(); - displayFrames = displayFrames.Concat(framesStartingAtMod.Skip(displayFrames.Length).Take(1)).ToArray(); - - // build stack trace - StringBuilder str = new(); - foreach (var frame in displayFrames) - str.Append(new StackTrace(frame.Frame)); - return str.ToString().TrimEnd(); - } - } -} diff --git a/src/SMAPI/Framework/DeprecationWarning.cs b/src/SMAPI/Framework/DeprecationWarning.cs deleted file mode 100644 index 1e83f679..00000000 --- a/src/SMAPI/Framework/DeprecationWarning.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Diagnostics; - -namespace StardewModdingAPI.Framework -{ - /// A deprecation warning for a mod. - internal class DeprecationWarning - { - /********* - ** Accessors - *********/ - /// The affected mod. - public IModMetadata? Mod { get; } - - /// Get the display name for the affected mod. - public string ModName => this.Mod?.DisplayName ?? ""; - - /// A noun phrase describing what is deprecated. - public string NounPhrase { get; } - - /// The SMAPI version which deprecated it. - public string Version { get; } - - /// The deprecation level for the affected code. - public DeprecationLevel Level { get; } - - /// The stack trace when the deprecation warning was raised. - public StackTrace StackTrace { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The affected mod. - /// A noun phrase describing what is deprecated. - /// The SMAPI version which deprecated it. - /// The deprecation level for the affected code. - /// The stack trace when the deprecation warning was raised. - public DeprecationWarning(IModMetadata? mod, string nounPhrase, string version, DeprecationLevel level, StackTrace stackTrace) - { - this.Mod = mod; - this.NounPhrase = nounPhrase; - this.Version = version; - this.Level = level; - this.StackTrace = stackTrace; - } - } -} diff --git a/src/SMAPI/Framework/Deprecations/DeprecationLevel.cs b/src/SMAPI/Framework/Deprecations/DeprecationLevel.cs new file mode 100644 index 00000000..8b15b59a --- /dev/null +++ b/src/SMAPI/Framework/Deprecations/DeprecationLevel.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Framework.Deprecations +{ + /// Indicates how deprecated something is. + internal enum DeprecationLevel + { + /// It's deprecated but won't be removed soon. Mod authors have some time to update their mods. Deprecation warnings should be logged, but not written to the console. + Notice, + + /// Mods should no longer be using it. Deprecation messages should be debug entries in the console. + Info, + + /// The code will be removed soon. Deprecation messages should be warnings in the console. + PendingRemoval + } +} diff --git a/src/SMAPI/Framework/Deprecations/DeprecationManager.cs b/src/SMAPI/Framework/Deprecations/DeprecationManager.cs new file mode 100644 index 00000000..da17ce7e --- /dev/null +++ b/src/SMAPI/Framework/Deprecations/DeprecationManager.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace StardewModdingAPI.Framework.Deprecations +{ + /// Manages deprecation warnings. + internal class DeprecationManager + { + /********* + ** Fields + *********/ + /// The deprecations which have already been logged (as 'mod name::noun phrase::version'). + private readonly HashSet LoggedDeprecations = new(StringComparer.OrdinalIgnoreCase); + + /// Encapsulates monitoring and logging for a given module. + private readonly IMonitor Monitor; + + /// Tracks the installed mods. + private readonly ModRegistry ModRegistry; + + /// The queued deprecation warnings to display. + private readonly IList QueuedWarnings = new List(); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Encapsulates monitoring and logging for a given module. + /// Tracks the installed mods. + public DeprecationManager(IMonitor monitor, ModRegistry modRegistry) + { + this.Monitor = monitor; + this.ModRegistry = modRegistry; + } + + /// Get a mod for the closest assembly registered as a source of deprecation warnings. + /// Returns the source name, or null if no registered assemblies were found. + public IModMetadata? GetModFromStack() + { + return this.ModRegistry.GetFromStack(); + } + + /// Get a mod from its unique ID. + /// The mod's unique ID. + public IModMetadata? GetMod(string modId) + { + return this.ModRegistry.Get(modId); + } + + /// Log a deprecation warning. + /// The mod which used the deprecated code, if known. + /// A noun phrase describing what is deprecated. + /// The SMAPI version which deprecated it. + /// How deprecated the code is. + public void Warn(IModMetadata? source, string nounPhrase, string version, DeprecationLevel severity) + { + // ignore if already warned + if (!this.MarkWarned(source, nounPhrase, version)) + return; + + // queue warning + var stack = new StackTrace(skipFrames: 1); // skip this method + this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity, stack)); + } + + /// A placeholder method used to track deprecated code for which a separate warning will be shown. + /// The SMAPI version which deprecated it. + /// How deprecated the code is. + public void PlaceholderWarn(string version, DeprecationLevel severity) { } + + /// Print any queued messages. + public void PrintQueued() + { + foreach (DeprecationWarning warning in this.QueuedWarnings.OrderBy(p => p.ModName).ThenBy(p => p.NounPhrase)) + { + // build message + string message = $"{warning.ModName} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version})."; + + // get log level + LogLevel level; + switch (warning.Level) + { + case DeprecationLevel.Notice: + level = LogLevel.Trace; + break; + + case DeprecationLevel.Info: + level = LogLevel.Debug; + break; + + case DeprecationLevel.PendingRemoval: + level = LogLevel.Warn; + break; + + default: + throw new NotSupportedException($"Unknown deprecation level '{warning.Level}'."); + } + + // log message + if (level == LogLevel.Trace) + this.Monitor.Log($"{message}\n{this.GetSimplifiedStackTrace(warning.StackTrace, warning.Mod)}", level); + else + { + this.Monitor.Log(message, level); + this.Monitor.Log(this.GetSimplifiedStackTrace(warning.StackTrace, warning.Mod), LogLevel.Debug); + } + } + + this.QueuedWarnings.Clear(); + } + + + /********* + ** Private methods + *********/ + /// Mark a deprecation warning as already logged. + /// The mod which used the deprecated code. + /// A noun phrase describing what is deprecated (e.g. "the Extensions.AsInt32 method"). + /// The SMAPI version which deprecated it. + /// Returns whether the deprecation was successfully marked as warned. Returns false if it was already marked. + private bool MarkWarned(IModMetadata? source, string nounPhrase, string version) + { + string key = $"{source?.DisplayName ?? ""}::{nounPhrase}::{version}"; + if (this.LoggedDeprecations.Contains(key)) + return false; + this.LoggedDeprecations.Add(key); + return true; + } + + /// Get the simplest stack trace which shows where in the mod the deprecated code was called from. + /// The stack trace. + /// The mod for which to show a stack trace. + private string GetSimplifiedStackTrace(StackTrace stack, IModMetadata? mod) + { + // unknown mod, show entire stack trace + if (mod == null) + return stack.ToString(); + + // get frame info + var frames = stack + .GetFrames() + .Select(frame => (Frame: frame, Mod: this.ModRegistry.GetFrom(frame))) + .ToArray(); + var modIds = new HashSet( + from frame in frames + let id = frame.Mod?.Manifest.UniqueID + where id != null + select id + ); + + // can't filter to the target mod + if (modIds.Count != 1 || !modIds.Contains(mod.Manifest.UniqueID)) + return stack.ToString(); + + // get stack frames for the target mod, plus one for context + var framesStartingAtMod = frames.SkipWhile(p => p.Mod == null).ToArray(); + var displayFrames = framesStartingAtMod.TakeWhile(p => p.Mod != null).ToArray(); + displayFrames = displayFrames.Concat(framesStartingAtMod.Skip(displayFrames.Length).Take(1)).ToArray(); + + // build stack trace + StringBuilder str = new(); + foreach (var frame in displayFrames) + str.Append(new StackTrace(frame.Frame)); + return str.ToString().TrimEnd(); + } + } +} diff --git a/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs b/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs new file mode 100644 index 00000000..38062daf --- /dev/null +++ b/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs @@ -0,0 +1,48 @@ +using System.Diagnostics; + +namespace StardewModdingAPI.Framework.Deprecations +{ + /// A deprecation warning for a mod. + internal class DeprecationWarning + { + /********* + ** Accessors + *********/ + /// The affected mod. + public IModMetadata? Mod { get; } + + /// Get the display name for the affected mod. + public string ModName => this.Mod?.DisplayName ?? ""; + + /// A noun phrase describing what is deprecated. + public string NounPhrase { get; } + + /// The SMAPI version which deprecated it. + public string Version { get; } + + /// The deprecation level for the affected code. + public DeprecationLevel Level { get; } + + /// The stack trace when the deprecation warning was raised. + public StackTrace StackTrace { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The affected mod. + /// A noun phrase describing what is deprecated. + /// The SMAPI version which deprecated it. + /// The deprecation level for the affected code. + /// The stack trace when the deprecation warning was raised. + public DeprecationWarning(IModMetadata? mod, string nounPhrase, string version, DeprecationLevel level, StackTrace stackTrace) + { + this.Mod = mod; + this.NounPhrase = nounPhrase; + this.Version = version; + this.Level = level; + this.StackTrace = stackTrace; + } + } +} diff --git a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs index e430fb1c..226a8d69 100644 --- a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs @@ -1,4 +1,5 @@ using System; +using StardewModdingAPI.Framework.Deprecations; namespace StardewModdingAPI.Framework.ModHelpers { diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index 534ac138..94a30bf1 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.ContentManagers; +using StardewModdingAPI.Framework.Deprecations; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; using StardewValley; diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 5b450c36..a23a9beb 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -1,6 +1,7 @@ using System; using System.IO; using StardewModdingAPI.Events; +using StardewModdingAPI.Framework.Deprecations; using StardewModdingAPI.Framework.Input; namespace StardewModdingAPI.Framework.ModHelpers diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 44853627..c208788a 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -20,6 +20,7 @@ using StardewModdingAPI.Enums; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.ContentManagers; +using StardewModdingAPI.Framework.Deprecations; using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Input; diff --git a/src/SMAPI/Utilities/PerScreen.cs b/src/SMAPI/Utilities/PerScreen.cs index 6c2e436b..1c4c56fe 100644 --- a/src/SMAPI/Utilities/PerScreen.cs +++ b/src/SMAPI/Utilities/PerScreen.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using StardewModdingAPI.Framework; +using StardewModdingAPI.Framework.Deprecations; namespace StardewModdingAPI.Utilities { -- cgit