Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prompt for client upgrade when newer spec is found #4026

Merged
merged 1 commit into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions Core/Meta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Linq;
using System.Reflection;

using CKAN.Versioning;

namespace CKAN
{
public static class Meta
Expand All @@ -16,6 +18,8 @@ public static string GetProductName()
.GetAssemblyAttribute<AssemblyProductAttribute>()
.Product;

public static readonly ModuleVersion ReleaseVersion = new ModuleVersion(GetVersion());

public static string GetVersion(VersionFormat format = VersionFormat.Normal)
{
var version = Assembly
Expand All @@ -25,8 +29,6 @@ public static string GetVersion(VersionFormat format = VersionFormat.Normal)

switch (format)
{
case VersionFormat.Short:
return $"v{version.UpToCharacters(shortDelimiters)}";
case VersionFormat.Normal:
return "v" + Assembly.GetExecutingAssembly()
.GetAssemblyAttribute<AssemblyFileVersionAttribute>()
Expand All @@ -38,15 +40,6 @@ public static string GetVersion(VersionFormat format = VersionFormat.Normal)
}
}

private static readonly char[] shortDelimiters = new char[] { '-', '+' };

private static string UpToCharacters(this string orig, char[] what)
=> orig.UpToIndex(orig.IndexOfAny(what));

private static string UpToIndex(this string orig, int index)
=> index == -1 ? orig
: orig.Substring(0, index);

private static T GetAssemblyAttribute<T>(this Assembly assembly)
=> (T)assembly.GetCustomAttributes(typeof(T), false)
.First();
Expand Down
31 changes: 22 additions & 9 deletions Core/Repositories/RepositoryData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ namespace CKAN
using ArchiveList = Tuple<List<CkanModule>,
SortedDictionary<string, int>,
GameVersion[],
Repository[]>;
Repository[],
bool>;

/// <summary>
/// Represents everything we retrieve from one metadata repository
Expand Down Expand Up @@ -63,6 +64,12 @@ public class RepositoryData
[JsonProperty("repositories", NullValueHandling = NullValueHandling.Ignore)]
public readonly Repository[] Repositories;

/// <summary>
/// true if any module we found requires a newer client version, false otherwise
/// </summary>
[JsonIgnore]
public readonly bool UnsupportedSpec;

private RepositoryData(Dictionary<string, AvailableModule> modules,
SortedDictionary<string, int> counts,
GameVersion[] versions,
Expand All @@ -84,14 +91,16 @@ private RepositoryData(Dictionary<string, AvailableModule> modules,
public RepositoryData(IEnumerable<CkanModule> modules,
SortedDictionary<string, int> counts,
IEnumerable<GameVersion> versions,
IEnumerable<Repository> repos)
IEnumerable<Repository> repos,
bool unsupportedSpec)
: this(modules?.GroupBy(m => m.identifier)
.ToDictionary(grp => grp.Key,
grp => new AvailableModule(grp.Key, grp)),
counts ?? new SortedDictionary<string, int>(),
(versions ?? Enumerable.Empty<GameVersion>()).ToArray(),
(repos ?? Enumerable.Empty<Repository>()).ToArray())
{
UnsupportedSpec = unsupportedSpec;
}

[JsonConstructor]
Expand Down Expand Up @@ -192,8 +201,9 @@ private static RepositoryData FromTarGz(string path, IGame game, IProgress<long>
(List<CkanModule> modules,
SortedDictionary<string, int> counts,
GameVersion[] versions,
Repository[] repos) = AggregateArchiveEntries(archiveEntriesFromTar(tarStream, game));
return new RepositoryData(modules, counts, versions, repos);
Repository[] repos,
bool unsupSpec) = AggregateArchiveEntries(archiveEntriesFromTar(tarStream, game));
return new RepositoryData(modules, counts, versions, repos, unsupSpec);
}
}

Expand Down Expand Up @@ -249,9 +259,10 @@ private static RepositoryData FromZip(string path, IGame game, IProgress<long> p
(List<CkanModule> modules,
SortedDictionary<string, int> counts,
GameVersion[] versions,
Repository[] repos) = AggregateArchiveEntries(archiveEntriesFromZip(zipfile, game));
Repository[] repos,
bool unsupSpec) = AggregateArchiveEntries(archiveEntriesFromZip(zipfile, game));
zipfile.Close();
return new RepositoryData(modules, counts, versions, repos);
return new RepositoryData(modules, counts, versions, repos, unsupSpec);
}
}

Expand All @@ -266,7 +277,7 @@ private static ParallelQuery<ArchiveEntry> archiveEntriesFromZip(ZipFile zipfile
entry.Offset));

private static ArchiveList AggregateArchiveEntries(ParallelQuery<ArchiveEntry> entries)
=> entries.Aggregate(new ArchiveList(new List<CkanModule>(), null, null, null),
=> entries.Aggregate(new ArchiveList(new List<CkanModule>(), null, null, null, false),
(subtotal, item) =>
item == null
? subtotal
Expand All @@ -276,12 +287,14 @@ private static ArchiveList AggregateArchiveEntries(ParallelQuery<ArchiveEntry> e
: subtotal.Item1.Append(item.Item1).ToList(),
subtotal.Item2 ?? item.Item2,
subtotal.Item3 ?? item.Item3,
subtotal.Item4 ?? item.Item4),
subtotal.Item4 ?? item.Item4,
subtotal.Item5 || item.Item1 == null),
(total, subtotal)
=> new ArchiveList(total.Item1.Concat(subtotal.Item1).ToList(),
total.Item2 ?? subtotal.Item2,
total.Item3 ?? subtotal.Item3,
total.Item4 ?? subtotal.Item4),
total.Item4 ?? subtotal.Item4,
total.Item5 || subtotal.Item5),
total => total);

private static ArchiveEntry getArchiveEntry(string filename,
Expand Down
5 changes: 4 additions & 1 deletion Core/Repositories/RepositoryDataManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public enum UpdateResult
Failed,
Updated,
NoChanges,
OutdatedClient,
}

/// <summary>
Expand Down Expand Up @@ -218,7 +219,9 @@ public UpdateResult Update(Repository[] repos,
downloader.onOneCompleted -= setETag;
}

return UpdateResult.Updated;
return repositoriesData.Values.Any(repoData => repoData.UnsupportedSpec)
? UpdateResult.OutdatedClient
: UpdateResult.Updated;
}

/// <summary>
Expand Down
7 changes: 1 addition & 6 deletions Core/Types/CkanModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -700,12 +700,7 @@ bool IEquatable<CkanModule>.Equals(CkanModule other)
/// Returns true if we support at least spec_version of the CKAN spec.
/// </summary>
internal static bool IsSpecSupported(ModuleVersion spec_version)
{
// This could be a read-only state variable; do we have those in C#?
ModuleVersion release = new ModuleVersion(Meta.GetVersion(VersionFormat.Short));

return release == null || release.IsGreaterThan(spec_version);
}
=> Meta.ReleaseVersion.IsGreaterThan(spec_version);

/// <summary>
/// Returns true if we support the CKAN spec used by this module.
Expand Down
2 changes: 1 addition & 1 deletion Core/Types/ModuleInstallDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ private void EnsurePattern()
}
else
{
throw new UnsupportedKraken(Properties.Resources.ModuleInstallDescriptorRequireFileFind);
throw new Kraken(Properties.Resources.ModuleInstallDescriptorRequireFileFind);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion Core/VersionFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ namespace CKAN
{
public enum VersionFormat
{
Short,
Normal,
Full
}
Expand Down
2 changes: 1 addition & 1 deletion GUI/Dialogs/NewUpdateDialog.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion GUI/Dialogs/NewUpdateDialog.resx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="label1.Text" xml:space="preserve"><value>Version:</value></data>
<data name="VersionLabel.Text" xml:space="preserve"><value>v0.0.0</value></data>
<data name="InstallUpdateButton.Text" xml:space="preserve"><value>Install</value></data>
<data name="CancelUpdateButton.Text" xml:space="preserve"><value>Not now</value></data>
<data name="$this.Text" xml:space="preserve"><value>A new version of CKAN is available</value></data>
Expand Down
2 changes: 1 addition & 1 deletion GUI/Dialogs/SettingsDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ private void CheckForUpdatesButton_Click(object sender, EventArgs e)

private void InstallUpdateButton_Click(object sender, EventArgs e)
{
if (AutoUpdate.CanUpdate)
if (Main.Instance.CheckForCKANUpdate())
{
Hide();
Main.Instance.UpdateCKAN();
Expand Down
7 changes: 6 additions & 1 deletion GUI/Main/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,12 @@ private void CurrentInstanceUpdated()
.Resolve<IConfiguration>(),
configuration);

bool autoUpdating = CheckForCKANUpdate();
bool autoUpdating = configuration.CheckForUpdatesOnLaunch
&& CheckForCKANUpdate();
if (autoUpdating)
{
UpdateCKAN();
}

var pluginsPath = Path.Combine(CurrentInstance.CkanDir(), "Plugins");
if (!Directory.Exists(pluginsPath))
Expand Down
12 changes: 5 additions & 7 deletions GUI/Main/MainAutoUpdate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,24 @@ private void AutoUpdatePrompts(IConfiguration coreConfig,
/// <returns>
/// true if update found, false otherwise.
/// </returns>
private bool CheckForCKANUpdate()
public bool CheckForCKANUpdate()
{
if (configuration.CheckForUpdatesOnLaunch && AutoUpdate.CanUpdate)
if (AutoUpdate.CanUpdate)
{
try
{
log.Info("Making auto-update call");
var mainConfig = ServiceLocator.Container.Resolve<IConfiguration>();
var update = updater.GetUpdate(mainConfig.DevBuilds ?? false);
var latestVersion = update.Version;
var currentVersion = new ModuleVersion(Meta.GetVersion());

if (latestVersion.IsGreaterThan(currentVersion))
if (latestVersion.IsGreaterThan(Meta.ReleaseVersion))
{
log.Debug("Found higher ckan version");
log.DebugFormat("Found higher CKAN version: {0}", latestVersion);
var releaseNotes = update.ReleaseNotes;
var dialog = new NewUpdateDialog(latestVersion.ToString(), releaseNotes);
if (dialog.ShowDialog(this) == DialogResult.OK)
{
UpdateCKAN();
return true;
}
}
Expand Down Expand Up @@ -90,7 +88,7 @@ public void UpdateCKAN()
Wait.SetDescription(string.Format(Properties.Resources.MainUpgradingTo,
update.Version));

log.Info("Start ckan update");
log.Info("Starting CKAN update");
Wait.StartWaiting((sender, args) => updater.StartUpdateProcess(true, mainConfig.DevBuilds ?? false, currentUser),
UpdateReady,
false,
Expand Down
16 changes: 16 additions & 0 deletions GUI/Main/MainRepo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,22 @@ private void PostUpdateRepo(object sender, RunWorkerCompletedEventArgs e)
}
break;


case RepositoryDataManager.UpdateResult.OutdatedClient:
currentUser.RaiseMessage(Properties.Resources.MainRepoOutdatedClient);
if (CheckForCKANUpdate())
{
UpdateCKAN();
}
else
{
// No update available or user said no. Proceed as normal.
ShowRefreshQuestion();
UpgradeNotification();
RefreshModList(false, oldModules);
}
break;

case RepositoryDataManager.UpdateResult.Updated:
default:
currentUser.RaiseMessage(Properties.Resources.MainRepoSuccess);
Expand Down
1 change: 1 addition & 0 deletions GUI/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ If you suspect a bug in the client: https://github.com/KSP-CKAN/CKAN/issues/new/
<data name="MainRepoUpToDate" xml:space="preserve"><value>Repositories already up to date.</value></data>
<data name="MainRepoFailed" xml:space="preserve"><value>Repository update failed!</value></data>
<data name="MainRepoSuccess" xml:space="preserve"><value>Repositories successfully updated.</value></data>
<data name="MainRepoOutdatedClient" xml:space="preserve"><value>Repositories updated, but found modules that require a new version of CKAN. Checking for updates...</value></data>
<data name="MainRepoAutoRefreshPrompt" xml:space="preserve"><value>Would you like CKAN to refresh the modlist every time it is loaded? (You can always manually refresh using the button up top.)</value></data>
<data name="MainRepoBalloonTipDetails" xml:space="preserve"><value>{0} update(s) available</value></data>
<data name="MainRepoBalloonTipTooltip" xml:space="preserve"><value>Click to upgrade</value></data>
Expand Down
2 changes: 1 addition & 1 deletion GlobalAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[assembly: AssemblyProduct("CKAN")]
[assembly: AssemblyCompany("CKAN Contributors")]
[assembly: AssemblyCopyright("Copyright © 2014–2023")]
[assembly: AssemblyCopyright("Copyright © 2014–2024")]

#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
Expand Down
Loading