diff --git a/ConsoleUI/AuthTokenListScreen.cs b/ConsoleUI/AuthTokenListScreen.cs
index 7ed330888..3f0f7b62a 100644
--- a/ConsoleUI/AuthTokenListScreen.cs
+++ b/ConsoleUI/AuthTokenListScreen.cs
@@ -82,7 +82,7 @@ public AuthTokenScreen(ConsoleTheme theme) : base(theme)
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/ConsoleUI/DeleteDirectoriesScreen.cs b/ConsoleUI/DeleteDirectoriesScreen.cs
index 3084005cf..5e1d43bb2 100644
--- a/ConsoleUI/DeleteDirectoriesScreen.cs
+++ b/ConsoleUI/DeleteDirectoriesScreen.cs
@@ -122,7 +122,7 @@ directories.Selection is null
///
/// Put CKAN 1.25.5 in top left corner
///
- protected override string LeftHeader() => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ protected override string LeftHeader() => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Show the Delete Directories header
diff --git a/ConsoleUI/DependencyScreen.cs b/ConsoleUI/DependencyScreen.cs
index 4db1fb831..c21ec3c3b 100644
--- a/ConsoleUI/DependencyScreen.cs
+++ b/ConsoleUI/DependencyScreen.cs
@@ -142,7 +142,7 @@ public DependencyScreen(ConsoleTheme theme,
///
/// Put CKAN 1.25.5 in top left corner
///
- protected override string LeftHeader() => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ protected override string LeftHeader() => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/ConsoleUI/ExitScreen.cs b/ConsoleUI/ExitScreen.cs
index d1a183e04..cf8f15dc2 100644
--- a/ConsoleUI/ExitScreen.cs
+++ b/ConsoleUI/ExitScreen.cs
@@ -49,8 +49,8 @@ private void Draw(ConsoleTheme theme)
Console.Clear();
// Specially formatted snippets
- var ckanPiece = new FancyLinePiece(Meta.GetProductName(), theme.ExitInnerBg, theme.ExitHighlightFg);
- var ckanVersionPiece = new FancyLinePiece($"{Meta.GetProductName()} {Meta.GetVersion()}", theme.ExitInnerBg, theme.ExitHighlightFg);
+ var ckanPiece = new FancyLinePiece(Meta.ProductName, theme.ExitInnerBg, theme.ExitHighlightFg);
+ var ckanVersionPiece = new FancyLinePiece($"{Meta.ProductName} {Meta.GetVersion()}", theme.ExitInnerBg, theme.ExitHighlightFg);
var releaseLinkPiece = new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/releases/latest", theme.ExitInnerBg, theme.ExitLinkFg);
var issuesLinkPiece = new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/issues", theme.ExitInnerBg, theme.ExitLinkFg);
var authorsLinkPiece = new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/graphs/contributors", theme.ExitInnerBg, theme.ExitLinkFg);
diff --git a/ConsoleUI/GameInstanceListScreen.cs b/ConsoleUI/GameInstanceListScreen.cs
index 65f621d02..d136cdb59 100644
--- a/ConsoleUI/GameInstanceListScreen.cs
+++ b/ConsoleUI/GameInstanceListScreen.cs
@@ -168,7 +168,7 @@ public GameInstanceListScreen(ConsoleTheme theme,
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/ConsoleUI/GameInstanceScreen.cs b/ConsoleUI/GameInstanceScreen.cs
index 3af3d63ea..814319f5b 100644
--- a/ConsoleUI/GameInstanceScreen.cs
+++ b/ConsoleUI/GameInstanceScreen.cs
@@ -56,7 +56,7 @@ protected GameInstanceScreen(ConsoleTheme theme, GameInstanceManager mgr, string
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Return whether the fields currently are valid.
diff --git a/ConsoleUI/InstallFiltersScreen.cs b/ConsoleUI/InstallFiltersScreen.cs
index 89605aee5..79f575786 100644
--- a/ConsoleUI/InstallFiltersScreen.cs
+++ b/ConsoleUI/InstallFiltersScreen.cs
@@ -98,7 +98,7 @@ public InstallFiltersScreen(ConsoleTheme theme, IConfiguration globalConfig, Gam
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/ConsoleUI/ModInfoScreen.cs b/ConsoleUI/ModInfoScreen.cs
index 5a277045d..a45b6891d 100644
--- a/ConsoleUI/ModInfoScreen.cs
+++ b/ConsoleUI/ModInfoScreen.cs
@@ -226,7 +226,7 @@ public ModInfoScreen(ConsoleTheme theme,
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/ConsoleUI/ModListScreen.cs b/ConsoleUI/ModListScreen.cs
index b426ef18a..cbac86c35 100644
--- a/ConsoleUI/ModListScreen.cs
+++ b/ConsoleUI/ModListScreen.cs
@@ -381,7 +381,7 @@ is int i and > 0
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/ConsoleUI/ProgressScreen.cs b/ConsoleUI/ProgressScreen.cs
index 54f1f65e5..3df28ff08 100644
--- a/ConsoleUI/ProgressScreen.cs
+++ b/ConsoleUI/ProgressScreen.cs
@@ -46,7 +46,7 @@ public ProgressScreen(ConsoleTheme theme, string descrip, string initMsg = "")
/// Put CKAN 1.25.5 in upper left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description of what we're doing in top center
diff --git a/ConsoleUI/RepoScreen.cs b/ConsoleUI/RepoScreen.cs
index a55448f7b..9a131838a 100644
--- a/ConsoleUI/RepoScreen.cs
+++ b/ConsoleUI/RepoScreen.cs
@@ -80,7 +80,7 @@ protected RepoScreen(ConsoleTheme theme,
/// Put CKAN 1.25.5 in top left corner
///
protected override string LeftHeader()
- => $"{Meta.GetProductName()} {Meta.GetVersion()}";
+ => $"{Meta.ProductName} {Meta.GetVersion()}";
///
/// Put description in top center
diff --git a/Core/CKANPathUtils.cs b/Core/CKANPathUtils.cs
index bd226ec16..ec2c8f5fc 100644
--- a/Core/CKANPathUtils.cs
+++ b/Core/CKANPathUtils.cs
@@ -15,7 +15,7 @@ public static class CKANPathUtils
///
public static readonly string AppDataPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
- Meta.GetProductName());
+ Meta.ProductName);
private static readonly ILog log = LogManager.GetLogger(typeof(CKANPathUtils));
diff --git a/Core/Meta.cs b/Core/Meta.cs
index 6bd1dd220..4e432105c 100644
--- a/Core/Meta.cs
+++ b/Core/Meta.cs
@@ -1,7 +1,8 @@
-using System;
using System.Linq;
using System.Reflection;
+using System.Text.RegularExpressions;
+using CKAN.Extensions;
using CKAN.Versioning;
namespace CKAN
@@ -13,37 +14,40 @@ public static class Meta
/// so we don't have to embed that string in many places
///
/// "CKAN"
- public static string GetProductName()
- => Assembly.GetExecutingAssembly()
- .GetAssemblyAttribute()
- .Product;
+ public static readonly string ProductName =
+ Assembly.GetExecutingAssembly()
+ .GetAssemblyAttribute()
+ .Product;
public static readonly ModuleVersion ReleaseVersion = new ModuleVersion(GetVersion());
- public static bool IsNetKAN
- => Assembly.GetExecutingAssembly()
- .GetAssemblyAttribute()
- .Title.Contains("NetKAN");
+ public static readonly ModuleVersion SpecVersion =
+ // A dev build always has an odd patch version, and
+ // an odd number always ends with an odd digit in base 10
+ new Regex(@"^(?v\d+\.)(?\d+)\.\d*[13579]\.")
+ .TryMatch(ReleaseVersion.ToString(), out Match? m)
+ && int.TryParse(m.Groups["minor"].Value, out int minor)
+ ? new ModuleVersion($"{m.Groups["prefix"]}{minor + 1}.999")
+ : ReleaseVersion;
- public static string GetVersion(VersionFormat format = VersionFormat.Normal)
- {
- var version = Assembly
- .GetExecutingAssembly()
- .GetAssemblyAttribute()
- .InformationalVersion;
+ public static readonly bool IsNetKAN =
+ Assembly.GetExecutingAssembly()
+ .GetAssemblyAttribute()
+ .Title.Contains("NetKAN");
- switch (format)
+ public static string GetVersion(VersionFormat format = VersionFormat.Normal)
+ => "v" + (format switch
{
- case VersionFormat.Normal:
- return "v" + Assembly.GetExecutingAssembly()
- .GetAssemblyAttribute()
- .Version;
- case VersionFormat.Full:
- return $"v{version}";
- default:
- throw new ArgumentOutOfRangeException(nameof(format), format, null);
- }
- }
+ VersionFormat.Full =>
+ Assembly.GetExecutingAssembly()
+ .GetAssemblyAttribute()
+ .InformationalVersion,
+
+ VersionFormat.Normal or _ =>
+ Assembly.GetExecutingAssembly()
+ .GetAssemblyAttribute()
+ .Version,
+ });
private static T GetAssemblyAttribute(this Assembly assembly)
=> (T)assembly.GetCustomAttributes(typeof(T), false)
diff --git a/Core/Types/CkanModule.cs b/Core/Types/CkanModule.cs
index ccca9f4ba..44d37a6cd 100644
--- a/Core/Types/CkanModule.cs
+++ b/Core/Types/CkanModule.cs
@@ -680,7 +680,7 @@ bool IEquatable.Equals(CkanModule? other)
/// Returns true if we support at least spec_version of the CKAN spec.
///
internal static bool IsSpecSupported(ModuleVersion spec_version)
- => Meta.IsNetKAN || Meta.ReleaseVersion.IsGreaterThan(spec_version);
+ => Meta.IsNetKAN || Meta.SpecVersion.IsGreaterThan(spec_version);
///
/// Returns true if we support the CKAN spec used by this module.
diff --git a/GUI/Main/Main.cs b/GUI/Main/Main.cs
index 4412bc008..c502e1b47 100644
--- a/GUI/Main/Main.cs
+++ b/GUI/Main/Main.cs
@@ -142,8 +142,8 @@ public Main(string[] cmdlineArgs,
// Set the window name and class for X11
if (Platform.IsX11)
{
- HandleCreated += (sender, e) => X11.SetWMClass(Meta.GetProductName(),
- Meta.GetProductName(), Handle);
+ HandleCreated += (sender, e) => X11.SetWMClass(Meta.ProductName,
+ Meta.ProductName, Handle);
}
currentUser = new GUIUser(this, Wait, StatusLabel, StatusProgress);
@@ -427,8 +427,8 @@ private void CurrentInstanceUpdated()
Util.Invoke(this, () =>
{
- Text = $"{Meta.GetProductName()} {Meta.GetVersion()} - {CurrentInstance.game.ShortName} {CurrentInstance.Version()} -- {Platform.FormatPath(CurrentInstance.GameDir())}";
- minimizeNotifyIcon.Text = $"{Meta.GetProductName()} - {CurrentInstance.Name}";
+ Text = $"{Meta.ProductName} {Meta.GetVersion()} - {CurrentInstance.game.ShortName} {CurrentInstance.Version()} -- {Platform.FormatPath(CurrentInstance.GameDir())}";
+ minimizeNotifyIcon.Text = $"{Meta.ProductName} - {CurrentInstance.Name}";
UpdateStatusBar();
});