Browse Source

Merge pull request #152 from js6pak/semver

Add semantic versioning
Geoffrey Horsington 3 years ago
parent
commit
821ad5fe07

+ 1 - 0
BepInEx.Core/BepInEx.Core.csproj

@@ -27,6 +27,7 @@
     <PackageReference Include="HarmonyX" Version="2.1.1" />
     <PackageReference Include="Mono.Cecil" Version="0.10.4" />
     <PackageReference Include="MonoMod.Utils" Version="20.11.5.1" />
+    <PackageReference Include="SemanticVersioning" Version="1.3.0" />
   </ItemGroup>
   <ItemGroup>
     <Compile Remove="Contract\IPlugin.cs" />

+ 5 - 6
BepInEx.Core/Bootstrap/BaseChainloader.cs

@@ -6,6 +6,7 @@ using System.Reflection;
 using System.Text;
 using System.Text.RegularExpressions;
 using BepInEx.Configuration;
+using BepInEx.Core;
 using BepInEx.Logging;
 using Mono.Cecil;
 
@@ -15,7 +16,7 @@ namespace BepInEx.Bootstrap
 	{
 		#region Contract
 
-		protected virtual string ConsoleTitle => $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Paths.ProcessName}";
+		protected virtual string ConsoleTitle => $"BepInEx {Paths.BepInExVersion} - {Paths.ProcessName}";
 
 		private bool _initialized = false;
 
@@ -159,7 +160,7 @@ namespace BepInEx.Bootstrap
 				var sortedPlugins = ModifyLoadOrder(plugins);
 
 				var invalidPlugins = new HashSet<string>();
-				var processedPlugins = new Dictionary<string, Version>();
+				var processedPlugins = new Dictionary<string, SemVer.Version>();
 				var loadedAssemblies = new Dictionary<string, Assembly>();
 
 				foreach (var plugin in sortedPlugins)
@@ -173,7 +174,7 @@ namespace BepInEx.Bootstrap
 
 						// If the dependency wasn't already processed, it's missing altogether
 						bool dependencyExists = processedPlugins.TryGetValue(dependency.DependencyGUID, out var pluginVersion);
-						if (!dependencyExists || pluginVersion < dependency.MinimumVersion)
+						if (!dependencyExists || (dependency.VersionRange != null && !dependency.VersionRange.IsSatisfied(pluginVersion)))
 						{
 							// If the dependency is hard, collect it into a list to show
 							if (IsHardDependency(dependency))
@@ -201,10 +202,8 @@ namespace BepInEx.Bootstrap
 
 					if (missingDependencies.Count != 0)
 					{
-						bool IsEmptyVersion(Version v) => v.Major == 0 && v.Minor == 0 && v.Build <= 0 && v.Revision <= 0;
-
 						string message = $@"Could not load [{plugin}] because it has missing dependencies: {
-								string.Join(", ", missingDependencies.Select(s => IsEmptyVersion(s.MinimumVersion) ? s.DependencyGUID : $"{s.DependencyGUID} (v{s.MinimumVersion} or newer)").ToArray())
+								string.Join(", ", missingDependencies.Select(s => s.VersionRange == null ? s.DependencyGUID : $"{s.DependencyGUID} ({s.VersionRange})").ToArray())
 							}";
 						DependencyErrors.Add(message);
 						Logger.LogError(message);

+ 13 - 20
BepInEx.Core/Contract/Attributes.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using BepInEx.Bootstrap;
+using BepInEx.Core;
 using Mono.Cecil;
 
 namespace BepInEx
@@ -30,7 +31,7 @@ namespace BepInEx
 		/// <summary>
 		/// The specfic version of the plugin.
 		/// </summary>
-		public Version Version { get; protected set; }
+		public SemVer.Version Version { get; protected set; }
 
 		/// <param name="GUID">The unique identifier of the plugin. Should not change between plugin versions.</param>
 		/// <param name="Name">The user friendly name of the plugin. Is able to be changed between versions.</param>
@@ -39,15 +40,7 @@ namespace BepInEx
 		{
 			this.GUID = GUID;
 			this.Name = Name;
-
-			try
-			{
-				this.Version = new Version(Version);
-			}
-			catch
-			{
-				this.Version = null;
-			}
+			this.Version = SemVer.Version.TryParse(Version, out var v) ? v : null;
 		}
 
 		internal static BepInPlugin FromCecilType(TypeDefinition td)
@@ -95,9 +88,9 @@ namespace BepInEx
 		public DependencyFlags Flags { get; protected set; }
 
 		/// <summary>
-		/// The minimum version of the referenced plugin.
+		/// The version <see cref="SemVer.Range">range</see> of the referenced plugin.
 		/// </summary>
-		public Version MinimumVersion { get; protected set; }
+		public SemVer.Range VersionRange { get; protected set; }
 
 		/// <summary>
 		/// Marks this <see cref="BaseUnityPlugin"/> as depenant on another plugin. The other plugin will be loaded before this one.
@@ -109,19 +102,19 @@ namespace BepInEx
 		{
 			this.DependencyGUID = DependencyGUID;
 			this.Flags = Flags;
-			MinimumVersion = new Version();
+			VersionRange = null;
 		}
 
 		/// <summary>
 		/// Marks this <see cref="BaseUnityPlugin"/> as depenant on another plugin. The other plugin will be loaded before this one.
-		/// If the other plugin doesn't exist or is of a version below <see cref="MinimumVersion"/>, this plugin will not load and an error will be logged instead.
+		/// If the other plugin doesn't exist or is of a version not satisfying <see cref="VersionRange"/>, this plugin will not load and an error will be logged instead.
 		/// </summary>
-		/// <param name="DependencyGUID">The GUID of the referenced plugin.</param>
-		/// <param name="MinimumDependencyVersion">The minimum version of the referenced plugin.</param>
+		/// <param name="guid">The GUID of the referenced plugin.</param>
+		/// <param name="version">The version range of the referenced plugin.</param>
 		/// <remarks>When version is supplied the dependency is always treated as HardDependency</remarks>
-		public BepInDependency(string DependencyGUID, string MinimumDependencyVersion) : this(DependencyGUID)
+		public BepInDependency(string guid, string version) : this(guid)
 		{
-			MinimumVersion = new Version(MinimumDependencyVersion);
+			VersionRange = SemVer.Range.Parse(version);
 		}
 
 		internal static IEnumerable<BepInDependency> FromCecilType(TypeDefinition td)
@@ -140,14 +133,14 @@ namespace BepInEx
 		{
 			bw.Write(DependencyGUID);
 			bw.Write((int)Flags);
-			bw.Write(MinimumVersion.ToString());
+			bw.Write(VersionRange.ToString());
 		}
 
 		void ICacheable.Load(BinaryReader br)
 		{
 			DependencyGUID = br.ReadString();
 			Flags = (DependencyFlags)br.ReadInt32();
-			MinimumVersion = new Version(br.ReadString());
+			VersionRange = SemVer.Range.Parse(br.ReadString());
 		}
 	}
 

+ 3 - 0
BepInEx.Core/Paths.cs

@@ -1,5 +1,6 @@
 using System.IO;
 using System.Reflection;
+using BepInEx.Core;
 using MonoMod.Utils;
 
 namespace BepInEx
@@ -33,6 +34,8 @@ namespace BepInEx
 			PluginPath = Utility.CombinePaths(BepInExRootPath, pluginPath);
 		}
 
+		public static SemVer.Version BepInExVersion { get; } = SemVer.Version.Parse(typeof(Paths).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion);
+
 		/// <summary>
 		///     The directory that the core BepInEx DLLs reside in.
 		/// </summary>

+ 1 - 1
BepInEx.Preloader.Core/Logging/ChainloaderLogHelper.cs

@@ -9,7 +9,7 @@ namespace BepInEx.Preloader.Core.Logging
 	{
 		public static void PrintLogInfo(ManualLogSource log)
 		{
-			string consoleTitle = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Paths.ProcessName}";
+			string consoleTitle = $"BepInEx {Paths.BepInExVersion} - {Paths.ProcessName}";
 			log.LogMessage(consoleTitle);
 
 			if (ConsoleManager.ConsoleActive)