InstallUpdate pre-check failures should now show a nice error on the UI.
This commit is contained in:
parent
8833f1ad31
commit
7ce9f416d1
|
@ -280,7 +280,7 @@ namespace NzbDrone.Core.Test.UpdateTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_throw_when_install_cannot_be_started()
|
public void should_log_when_install_cannot_be_started()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Setup(c => c.FolderWritable(It.IsAny<string>()))
|
.Setup(c => c.FolderWritable(It.IsAny<string>()))
|
||||||
|
@ -288,7 +288,7 @@ namespace NzbDrone.Core.Test.UpdateTests
|
||||||
|
|
||||||
var updateArchive = Path.Combine(_sandboxFolder, _updatePackage.FileName);
|
var updateArchive = Path.Combine(_sandboxFolder, _updatePackage.FileName);
|
||||||
|
|
||||||
Assert.Throws<NzbDroneClientException>(() => Subject.Execute(new InstallUpdateCommand() { UpdatePackage = _updatePackage }));
|
Subject.Execute(new InstallUpdateCommand() { UpdatePackage = _updatePackage });
|
||||||
|
|
||||||
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_updatePackage.Url, updateArchive), Times.Never());
|
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_updatePackage.Url, updateArchive), Times.Never());
|
||||||
ExceptionVerification.ExpectedErrors(1);
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
|
|
|
@ -855,8 +855,10 @@
|
||||||
<Compile Include="Update\Commands\InstallUpdateCommand.cs" />
|
<Compile Include="Update\Commands\InstallUpdateCommand.cs" />
|
||||||
<Compile Include="Update\InstallUpdateService.cs" />
|
<Compile Include="Update\InstallUpdateService.cs" />
|
||||||
<Compile Include="Update\RecentUpdateProvider.cs" />
|
<Compile Include="Update\RecentUpdateProvider.cs" />
|
||||||
|
<Compile Include="Update\UpdateAbortedException.cs" />
|
||||||
<Compile Include="Update\UpdateChanges.cs" />
|
<Compile Include="Update\UpdateChanges.cs" />
|
||||||
<Compile Include="Update\UpdateCheckService.cs" />
|
<Compile Include="Update\UpdateCheckService.cs" />
|
||||||
|
<Compile Include="Update\UpdateFolderNotWritableException.cs" />
|
||||||
<Compile Include="Update\UpdateMechanism.cs" />
|
<Compile Include="Update\UpdateMechanism.cs" />
|
||||||
<Compile Include="Update\UpdatePackage.cs" />
|
<Compile Include="Update\UpdatePackage.cs" />
|
||||||
<Compile Include="Update\UpdatePackageAvailable.cs" />
|
<Compile Include="Update\UpdatePackageAvailable.cs" />
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
|
@ -10,13 +12,11 @@ using NzbDrone.Common.Instrumentation.Extensions;
|
||||||
using NzbDrone.Common.Processes;
|
using NzbDrone.Common.Processes;
|
||||||
using NzbDrone.Core.Backup;
|
using NzbDrone.Core.Backup;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Exceptions;
|
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
using NzbDrone.Core.Update.Commands;
|
using NzbDrone.Core.Update.Commands;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Update
|
namespace NzbDrone.Core.Update
|
||||||
{
|
{
|
||||||
|
|
||||||
public class InstallUpdateService : IExecute<ApplicationUpdateCommand>, IExecute<InstallUpdateCommand>
|
public class InstallUpdateService : IExecute<ApplicationUpdateCommand>, IExecute<InstallUpdateCommand>
|
||||||
{
|
{
|
||||||
private readonly ICheckUpdateService _checkUpdateService;
|
private readonly ICheckUpdateService _checkUpdateService;
|
||||||
|
@ -62,9 +62,7 @@ namespace NzbDrone.Core.Update
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool InstallUpdate(UpdatePackage updatePackage)
|
private void InstallUpdate(UpdatePackage updatePackage)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
EnsureAppDataSafety();
|
EnsureAppDataSafety();
|
||||||
|
|
||||||
|
@ -72,7 +70,7 @@ namespace NzbDrone.Core.Update
|
||||||
{
|
{
|
||||||
if (!_diskProvider.FolderWritable(_appFolderInfo.StartUpFolder))
|
if (!_diskProvider.FolderWritable(_appFolderInfo.StartUpFolder))
|
||||||
{
|
{
|
||||||
throw new ApplicationException(string.Format("Cannot install update because startup folder '{0}' is not writable by the user '{1}'.", _appFolderInfo.StartUpFolder, Environment.UserName));
|
throw new UpdateFolderNotWritableException("Cannot install update because startup folder '{0}' is not writable by the user '{1}'.", _appFolderInfo.StartUpFolder, Environment.UserName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +107,7 @@ namespace NzbDrone.Core.Update
|
||||||
if (OsInfo.IsNotWindows && _configFileProvider.UpdateMechanism == UpdateMechanism.Script)
|
if (OsInfo.IsNotWindows && _configFileProvider.UpdateMechanism == UpdateMechanism.Script)
|
||||||
{
|
{
|
||||||
InstallUpdateWithScript(updateSandboxFolder);
|
InstallUpdateWithScript(updateSandboxFolder);
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Info("Preparing client");
|
_logger.Info("Preparing client");
|
||||||
|
@ -117,17 +115,9 @@ namespace NzbDrone.Core.Update
|
||||||
updateSandboxFolder);
|
updateSandboxFolder);
|
||||||
|
|
||||||
_logger.Info("Starting update client {0}", _appFolderInfo.GetUpdateClientExePath());
|
_logger.Info("Starting update client {0}", _appFolderInfo.GetUpdateClientExePath());
|
||||||
_logger.ProgressInfo("NzbDrone will restart shortly.");
|
_logger.ProgressInfo("Sonarr will restart shortly.");
|
||||||
|
|
||||||
_processProvider.Start(_appFolderInfo.GetUpdateClientExePath(), GetUpdaterArgs(updateSandboxFolder));
|
_processProvider.Start(_appFolderInfo.GetUpdateClientExePath(), GetUpdaterArgs(updateSandboxFolder));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Update process failed", ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InstallUpdateWithScript(String updateSandboxFolder)
|
private void InstallUpdateWithScript(String updateSandboxFolder)
|
||||||
|
@ -165,7 +155,32 @@ namespace NzbDrone.Core.Update
|
||||||
if (_appFolderInfo.StartUpFolder.IsParentPath(_appFolderInfo.AppDataFolder) ||
|
if (_appFolderInfo.StartUpFolder.IsParentPath(_appFolderInfo.AppDataFolder) ||
|
||||||
_appFolderInfo.StartUpFolder.PathEquals(_appFolderInfo.AppDataFolder))
|
_appFolderInfo.StartUpFolder.PathEquals(_appFolderInfo.AppDataFolder))
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Update will cause AppData to be deleted, correct you configuration before proceeding");
|
throw new UpdateFailedException("You Sonarr configuration ('{0}') is being stored in application folder ('{1}') which will cause data lost during the upgrade. Please remove any symlinks or redirects before trying again.", _appFolderInfo.AppDataFolder, _appFolderInfo.StartUpFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteInstallUpdate(Command message, UpdatePackage package)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InstallUpdate(package);
|
||||||
|
|
||||||
|
message.Completed("Restarting Sonarr to apply updates");
|
||||||
|
}
|
||||||
|
catch (UpdateFolderNotWritableException ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Update process failed", ex);
|
||||||
|
message.Failed(ex, string.Format("Startup folder not writable by user '{0}'", Environment.UserName));
|
||||||
|
}
|
||||||
|
catch (UpdateVerificationFailedException ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Update process failed", ex);
|
||||||
|
message.Failed(ex, "Downloaded update package is corrupt");
|
||||||
|
}
|
||||||
|
catch (UpdateFailedException ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Update process failed", ex);
|
||||||
|
message.Failed(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,18 +191,20 @@ namespace NzbDrone.Core.Update
|
||||||
|
|
||||||
if (latestAvailable != null)
|
if (latestAvailable != null)
|
||||||
{
|
{
|
||||||
InstallUpdate(latestAvailable);
|
ExecuteInstallUpdate(message, latestAvailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(InstallUpdateCommand message)
|
public void Execute(InstallUpdateCommand message)
|
||||||
{
|
{
|
||||||
var success = InstallUpdate(message.UpdatePackage);
|
var latestAvailable = _checkUpdateService.AvailableUpdate();
|
||||||
|
|
||||||
if (!success)
|
if (latestAvailable == null || latestAvailable.Hash != message.UpdatePackage.Hash)
|
||||||
{
|
{
|
||||||
throw new NzbDroneClientException(System.Net.HttpStatusCode.Conflict, "Failed to install update");
|
throw new ApplicationException("Unknown or invalid update specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExecuteInstallUpdate(message, latestAvailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Update
|
||||||
|
{
|
||||||
|
public class UpdateFailedException : NzbDroneException
|
||||||
|
{
|
||||||
|
public UpdateFailedException(string message, params object[] args)
|
||||||
|
: base(message, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateFailedException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Update
|
||||||
|
{
|
||||||
|
public class UpdateFolderNotWritableException : UpdateFailedException
|
||||||
|
{
|
||||||
|
public UpdateFolderNotWritableException(string message, params object[] args)
|
||||||
|
: base(message, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateFolderNotWritableException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
namespace NzbDrone.Core.Update
|
namespace NzbDrone.Core.Update
|
||||||
{
|
{
|
||||||
public class UpdateVerificationFailedException : NzbDroneException
|
public class UpdateVerificationFailedException : UpdateFailedException
|
||||||
{
|
{
|
||||||
public UpdateVerificationFailedException(string message, params object[] args) : base(message, args)
|
public UpdateVerificationFailedException(string message, params object[] args)
|
||||||
|
: base(message, args)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateVerificationFailedException(string message) : base(message)
|
public UpdateVerificationFailedException(string message)
|
||||||
|
: base(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,15 @@ module.exports = Marionette.ItemView.extend({
|
||||||
id : this.model.id,
|
id : this.model.id,
|
||||||
hideAfter : 0
|
hideAfter : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var isManual = this.model.get('manual');
|
||||||
|
|
||||||
switch (this.model.get('state')) {
|
switch (this.model.get('state')) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
message.hideAfter = 4;
|
message.hideAfter = 4;
|
||||||
break;
|
break;
|
||||||
case 'failed':
|
case 'failed':
|
||||||
message.hideAfter = 4;
|
message.hideAfter = isManual ? 10 : 4;
|
||||||
message.type = 'error';
|
message.type = 'error';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue