diff --git a/src/Artemis.Storage/Entities/General/ReleaseEntity.cs b/src/Artemis.Storage/Entities/General/ReleaseEntity.cs index afae86286..3d10ed71b 100644 --- a/src/Artemis.Storage/Entities/General/ReleaseEntity.cs +++ b/src/Artemis.Storage/Entities/General/ReleaseEntity.cs @@ -7,6 +7,7 @@ public class ReleaseEntity public Guid Id { get; set; } public string Version { get; set; } + public string ReleaseId { get; set; } public ReleaseEntityStatus Status { get; set; } public DateTimeOffset? InstalledAt { get; set; } } @@ -15,5 +16,6 @@ public enum ReleaseEntityStatus { Queued, Installed, - Historical + Historical, + Unknown } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/ReleaseRepository.cs b/src/Artemis.Storage/Repositories/ReleaseRepository.cs index d052f550d..0c2d466dd 100644 --- a/src/Artemis.Storage/Repositories/ReleaseRepository.cs +++ b/src/Artemis.Storage/Repositories/ReleaseRepository.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Artemis.Storage.Entities.General; using Artemis.Storage.Repositories.Interfaces; using LiteDB; @@ -18,25 +17,25 @@ public class ReleaseRepository : IReleaseRepository _repository.Database.GetCollection().EnsureIndex(s => s.Status); } - public string GetQueuedVersion() + public ReleaseEntity GetQueuedVersion() { - return _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Queued).FirstOrDefault()?.Version; + return _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Queued).FirstOrDefault(); } - public string GetInstalledVersion() + public ReleaseEntity GetInstalledVersion() { - return _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Installed).FirstOrDefault()?.Version; + return _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Installed).FirstOrDefault(); } - public string GetPreviousInstalledVersion() + public ReleaseEntity GetPreviousInstalledVersion() { - return _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Historical).OrderByDescending(r => r.InstalledAt).FirstOrDefault()?.Version; + return _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Historical).OrderByDescending(r => r.InstalledAt).FirstOrDefault(); } - - public void QueueInstallation(string version) + + public void QueueInstallation(string version, string releaseId) { // Mark release as queued and add if missing - ReleaseEntity release = _repository.Query().Where(r => r.Version == version).FirstOrDefault() ?? new ReleaseEntity {Version = version}; + ReleaseEntity release = _repository.Query().Where(r => r.Version == version).FirstOrDefault() ?? new ReleaseEntity {Version = version, ReleaseId = releaseId}; release.Status = ReleaseEntityStatus.Queued; _repository.Upsert(release); } @@ -50,10 +49,7 @@ public class ReleaseRepository : IReleaseRepository _repository.Upsert(release); // Mark other releases as historical - List oldReleases = _repository.Query().Where(r => r.Version != version && r.Status == ReleaseEntityStatus.Installed).ToList(); - if (!oldReleases.Any()) - return; - + List oldReleases = _repository.Query().Where(r => r.Version != version && r.Status != ReleaseEntityStatus.Historical).ToList(); foreach (ReleaseEntity oldRelease in oldReleases) oldRelease.Status = ReleaseEntityStatus.Historical; _repository.Update(oldReleases); @@ -61,16 +57,20 @@ public class ReleaseRepository : IReleaseRepository public void DequeueInstallation() { - _repository.DeleteMany(r => r.Status == ReleaseEntityStatus.Queued); + // Mark all queued releases as unknown, until FinishInstallation is called we don't know the status + List queuedReleases = _repository.Query().Where(r => r.Status == ReleaseEntityStatus.Queued).ToList(); + foreach (ReleaseEntity queuedRelease in queuedReleases) + queuedRelease.Status = ReleaseEntityStatus.Unknown; + _repository.Update(queuedReleases); } } public interface IReleaseRepository : IRepository { - string GetQueuedVersion(); - string GetInstalledVersion(); - string GetPreviousInstalledVersion(); - void QueueInstallation(string version); + ReleaseEntity GetQueuedVersion(); + ReleaseEntity GetInstalledVersion(); + ReleaseEntity GetPreviousInstalledVersion(); + void QueueInstallation(string version, string releaseId); void FinishInstallation(string version); void DequeueInstallation(); } \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs b/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs index fa9ea76fa..024844bd6 100644 --- a/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs +++ b/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs @@ -128,7 +128,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider } // Queue an update in case the user interrupts the process after everything has been prepared - _updateService.QueueUpdate(releaseVersion); + _updateService.QueueUpdate(releaseVersion, releaseId); GetBuilderForRelease(releaseId, releaseVersion) .AddAudio(new ToastAudio {Silent = true}) diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseViewModel.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseViewModel.cs index bf959adbb..263ff055e 100644 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Updating/ReleaseViewModel.cs @@ -158,7 +158,7 @@ public class ReleaseViewModel : ActivatableViewModelBase { InstallationInProgress = true; await ReleaseInstaller.InstallAsync(_installerCts.Token); - _updateService.QueueUpdate(Version); + _updateService.QueueUpdate(Version, ReleaseId); InstallationFinished = true; } catch (Exception e) diff --git a/src/Artemis.UI/Services/Updating/IUpdateService.cs b/src/Artemis.UI/Services/Updating/IUpdateService.cs index 6b2571600..0da40b1a9 100644 --- a/src/Artemis.UI/Services/Updating/IUpdateService.cs +++ b/src/Artemis.UI/Services/Updating/IUpdateService.cs @@ -12,7 +12,7 @@ public interface IUpdateService : IArtemisUIService Task CacheLatestRelease(); Task CheckForUpdate(); - void QueueUpdate(string version); + void QueueUpdate(string version, string releaseId); ReleaseInstaller GetReleaseInstaller(string releaseId); void RestartForUpdate(bool silent); diff --git a/src/Artemis.UI/Services/Updating/UpdateService.cs b/src/Artemis.UI/Services/Updating/UpdateService.cs index d2cf9bef9..8e46d20b5 100644 --- a/src/Artemis.UI/Services/Updating/UpdateService.cs +++ b/src/Artemis.UI/Services/Updating/UpdateService.cs @@ -1,9 +1,11 @@ using System; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; +using Artemis.Storage.Entities.General; using Artemis.Storage.Repositories; using Artemis.UI.Shared.Services.MainWindow; using Artemis.WebClient.Updating; @@ -18,13 +20,13 @@ public class UpdateService : IUpdateService private const double UPDATE_CHECK_INTERVAL = 3_600_000; // once per hour private readonly PluginSetting _autoCheck; private readonly PluginSetting _autoInstall; - private readonly Platform _updatePlatform; + private readonly Func _getReleaseInstaller; private readonly ILogger _logger; - private readonly IUpdatingClient _updatingClient; private readonly IReleaseRepository _releaseRepository; private readonly Lazy _updateNotificationProvider; - private readonly Func _getReleaseInstaller; + private readonly Platform _updatePlatform; + private readonly IUpdatingClient _updatingClient; private bool _suspendAutoCheck; @@ -69,28 +71,46 @@ public class UpdateService : IUpdateService ProcessReleaseStatus(); } - public string Channel { get; } - public string? PreviousVersion { get; set; } - public IGetNextRelease_NextPublishedRelease? CachedLatestRelease { get; private set; } - private void ProcessReleaseStatus() { // If an update is queued, don't bother with anything else - string? queued = _releaseRepository.GetQueuedVersion(); + ReleaseEntity? queued = _releaseRepository.GetQueuedVersion(); if (queued != null) { // Remove the queued installation, in case something goes wrong then at least we don't end up in a loop - _logger.Information("Installing queued version {Version}", queued); + _logger.Information("Installing queued version {Version}", queued.Version); RestartForUpdate(true); return; } - + // If a different version was installed, mark it as such - string? installed = _releaseRepository.GetInstalledVersion(); - if (installed != Constants.CurrentVersion) + ReleaseEntity? installed = _releaseRepository.GetInstalledVersion(); + if (installed?.Version != Constants.CurrentVersion) _releaseRepository.FinishInstallation(Constants.CurrentVersion); - PreviousVersion = _releaseRepository.GetPreviousInstalledVersion(); + PreviousVersion = _releaseRepository.GetPreviousInstalledVersion()?.Version; + + if (!Directory.Exists(Path.Combine(Constants.DataFolder, "updating"))) + return; + + // Clean up the update folder, leaving only the last ZIP + foreach (string file in Directory.GetFiles(Path.Combine(Constants.DataFolder, "updating"))) + { + if (Path.GetExtension(file) != ".zip") + continue; + if (installed != null && Path.GetFileName(file) == $"{installed.ReleaseId}.zip") + continue; + + try + { + _logger.Debug("Cleaning up old update file at {FilePath}", file); + File.Delete(file); + } + catch (Exception e) + { + _logger.Warning(e, "Failed to clean up old update file at {FilePath}", file); + } + } } private void ShowUpdateNotification(IGetNextRelease_NextPublishedRelease release) @@ -120,6 +140,10 @@ public class UpdateService : IUpdateService } } + public string Channel { get; } + public string? PreviousVersion { get; set; } + public IGetNextRelease_NextPublishedRelease? CachedLatestRelease { get; private set; } + /// public async Task CacheLatestRelease() { @@ -159,11 +183,11 @@ public class UpdateService : IUpdateService } /// - public void QueueUpdate(string version) + public void QueueUpdate(string version, string releaseId) { - _releaseRepository.QueueInstallation(version); + _releaseRepository.QueueInstallation(version, releaseId); } - + /// public ReleaseInstaller GetReleaseInstaller(string releaseId) {