From 1270e464b35c4969b6aedc178d5686ce94648442 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Sat, 12 Nov 2011 20:07:06 -0800 Subject: [PATCH] More autoupdate code. --- NzbDrone.Common/DiskProvider.cs | 62 +++++++--- NzbDrone.Common/PathProvider.cs | 19 ++- NzbDrone.Common/ServiceProvider.cs | 10 ++ .../JobTests/BannerDownloadJobTest.cs | 1 - .../ExtractArchiveFixture.cs | 4 +- .../DiskProviderTests/FreeDiskSpaceTest.cs | 1 + .../ProviderTests/DiskScanProviderTest.cs | 1 + .../DiskScanProviderTest_ImportFile.cs | 1 + .../ProviderTests/MediaFileProviderTests.cs | 1 + .../ProcessDownloadFixture.cs | 1 + .../ProviderTests/RootDirProviderTest.cs | 1 + .../PreformUpdateFixture.cs | 39 +++--- NzbDrone.Core/Providers/Core/DiskProvider.cs | 109 +--------------- NzbDrone.Core/Providers/DiskScanProvider.cs | 1 + .../Providers/Jobs/BannerDownloadJob.cs | 1 - .../Providers/Jobs/PostDownloadScanJob.cs | 1 + .../Providers/PostDownloadProvider.cs | 1 + NzbDrone.Core/Providers/RootDirProvider.cs | 1 + NzbDrone.Core/Providers/UpdateProvider.cs | 11 +- .../UpdateProviderStartTest.cs | 116 +++++++++++++++++- .../UpdateProviderVerifyTest.cs | 28 ++--- NzbDrone.Update/Providers/UpdateProvider.cs | 68 +++++++--- .../Controllers/AddSeriesController.cs | 1 + .../Controllers/DirectoryController.cs | 8 +- NzbDrone.Web/Controllers/SystemController.cs | 2 +- 25 files changed, 285 insertions(+), 204 deletions(-) diff --git a/NzbDrone.Common/DiskProvider.cs b/NzbDrone.Common/DiskProvider.cs index fcec4573f..a3f49be2f 100644 --- a/NzbDrone.Common/DiskProvider.cs +++ b/NzbDrone.Common/DiskProvider.cs @@ -2,12 +2,20 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using NLog; namespace NzbDrone.Common { public class DiskProvider { + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, + out ulong lpFreeBytesAvailable, + out ulong lpTotalNumberOfBytes, + out ulong lpTotalNumberOfFreeBytes); + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public virtual bool FolderExists(string path) @@ -47,6 +55,25 @@ namespace NzbDrone.Common return Directory.CreateDirectory(path).FullName; } + public virtual void CopyDirectory(string source, string target) + { + Logger.Trace("Copying {0} -> {1}", source, target); + + var sourceFolder = new DirectoryInfo(source); + var targetFolder = new DirectoryInfo(target); + + if (!targetFolder.Exists) + { + targetFolder.Create(); + } + + foreach (var file in sourceFolder.GetFiles("*.*", SearchOption.AllDirectories)) + { + var destFile = Path.Combine(target, file.Name); + file.CopyTo(destFile, true); + } + } + public virtual void DeleteFile(string path) { File.Delete(path); @@ -77,30 +104,25 @@ namespace NzbDrone.Common Directory.Move(source, destination); } - public virtual void CopyDirectory(string source, string target) - { - Logger.Trace("Copying {0} -> {1}", source, target); - - var sourceFolder = new DirectoryInfo(source); - var targetFolder = new DirectoryInfo(target); - - if (!targetFolder.Exists) - { - targetFolder.Create(); - } - - foreach (var file in sourceFolder.GetFiles("*.*", SearchOption.AllDirectories)) - { - var destFile = Path.Combine(target, file.Name); - file.CopyTo(destFile, true); - } - } - public virtual void InheritFolderPermissions(string filename) { var fs = File.GetAccessControl(filename); fs.SetAccessRuleProtection(false, false); File.SetAccessControl(filename, fs); } + + public virtual ulong FreeDiskSpace(DirectoryInfo directoryInfo) + { + ulong freeBytesAvailable; + ulong totalNumberOfBytes; + ulong totalNumberOfFreeBytes; + + bool success = GetDiskFreeSpaceEx(directoryInfo.FullName, out freeBytesAvailable, out totalNumberOfBytes, + out totalNumberOfFreeBytes); + if (!success) + throw new System.ComponentModel.Win32Exception(); + + return freeBytesAvailable; + } } -} +} \ No newline at end of file diff --git a/NzbDrone.Common/PathProvider.cs b/NzbDrone.Common/PathProvider.cs index 9925e72b5..1dffafeba 100644 --- a/NzbDrone.Common/PathProvider.cs +++ b/NzbDrone.Common/PathProvider.cs @@ -17,11 +17,12 @@ namespace NzbDrone.Common private const string NZBDRONE_DB_FILE = "nzbdrone.sdf"; private const string LOG_DB_FILE = "log.sdf"; - public const string UPDATE_SANDBOX_FOLDER_NAME = "nzbdrone_update"; + private const string UPDATE_SANDBOX_FOLDER_NAME = "nzbdrone_update"; + private const string UPDATE_BACKUP_FOLDER_NAME = "nzbdrone_backup"; private readonly string _applicationPath; - + public PathProvider(EnviromentProvider enviromentProvider) { _applicationPath = enviromentProvider.ApplicationPath; @@ -29,7 +30,7 @@ namespace NzbDrone.Common public PathProvider() { - + } public virtual String LogPath @@ -103,9 +104,19 @@ namespace NzbDrone.Common get { return Path.Combine(AppData, "Cache"); } } - public string UpdateSandboxFolder + public virtual string UpdateSandboxFolder { get { return Path.Combine(SystemTemp, UPDATE_SANDBOX_FOLDER_NAME); } } + + public virtual string UpdatePackageFolder + { + get { return Path.Combine(UPDATE_SANDBOX_FOLDER_NAME, "NzbDrone"); } + } + + public virtual string UpdateBackUpFolder + { + get { return Path.Combine(UpdateSandboxFolder, UPDATE_BACKUP_FOLDER_NAME); } + } } } \ No newline at end of file diff --git a/NzbDrone.Common/ServiceProvider.cs b/NzbDrone.Common/ServiceProvider.cs index bf22ca256..c086af759 100644 --- a/NzbDrone.Common/ServiceProvider.cs +++ b/NzbDrone.Common/ServiceProvider.cs @@ -22,6 +22,16 @@ namespace NzbDrone.Common s => String.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase)); } + public virtual bool IsServiceRunning(string name) + { + Logger.Debug("Checking if '{0}' service is running", name); + + var service = ServiceController.GetServices() + .SingleOrDefault(s => String.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase)); + + return service != null && service.Status == ServiceControllerStatus.Running; + } + public virtual void Install(string serviceName) { diff --git a/NzbDrone.Core.Test/JobTests/BannerDownloadJobTest.cs b/NzbDrone.Core.Test/JobTests/BannerDownloadJobTest.cs index 3f37ffe38..4ff3f8e60 100644 --- a/NzbDrone.Core.Test/JobTests/BannerDownloadJobTest.cs +++ b/NzbDrone.Core.Test/JobTests/BannerDownloadJobTest.cs @@ -11,7 +11,6 @@ using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Repository; using NzbDrone.Core.Test.Framework; -using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider; namespace NzbDrone.Core.Test.JobTests { diff --git a/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ExtractArchiveFixture.cs b/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ExtractArchiveFixture.cs index 2c2103b61..9b0ffca27 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ExtractArchiveFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ExtractArchiveFixture.cs @@ -12,10 +12,10 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskProviderTests [Test] public void Should_extract_to_correct_folder() { - var diskProvider = new DiskProvider(); + var archiveProvider = new ArchiveProvider(); var destination = Path.Combine(TempFolder, "destination"); - diskProvider.ExtractArchive(GetTestFilePath("TestArchive.zip"), destination); + archiveProvider.ExtractArchive(GetTestFilePath("TestArchive.zip"), destination); var destinationFolder = new DirectoryInfo(destination); diff --git a/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs b/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs index 56e4c4934..7679538ee 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs @@ -7,6 +7,7 @@ using AutoMoq; using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Common; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Test.Framework; diff --git a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest.cs index 1a63cc487..1fc8d35bb 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest.cs @@ -4,6 +4,7 @@ using AutoMoq; using FizzWare.NBuilder; using Moq; using NUnit.Framework; +using NzbDrone.Common; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; diff --git a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest_ImportFile.cs b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest_ImportFile.cs index 9f37f54f0..caec1d8f1 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest_ImportFile.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTest_ImportFile.cs @@ -5,6 +5,7 @@ using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; diff --git a/NzbDrone.Core.Test/ProviderTests/MediaFileProviderTests.cs b/NzbDrone.Core.Test/ProviderTests/MediaFileProviderTests.cs index edfa1ac69..4b5f55391 100644 --- a/NzbDrone.Core.Test/ProviderTests/MediaFileProviderTests.cs +++ b/NzbDrone.Core.Test/ProviderTests/MediaFileProviderTests.cs @@ -6,6 +6,7 @@ using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Common; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; diff --git a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs index 8a8655838..77a87f7c6 100644 --- a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs @@ -7,6 +7,7 @@ using AutoMoq; using FizzWare.NBuilder; using Moq; using NUnit.Framework; +using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; diff --git a/NzbDrone.Core.Test/ProviderTests/RootDirProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/RootDirProviderTest.cs index 9c52f8fa8..af1179cf5 100644 --- a/NzbDrone.Core.Test/ProviderTests/RootDirProviderTest.cs +++ b/NzbDrone.Core.Test/ProviderTests/RootDirProviderTest.cs @@ -6,6 +6,7 @@ using AutoMoq; using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Common; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; diff --git a/NzbDrone.Core.Test/ProviderTests/UpdateProviderTests/PreformUpdateFixture.cs b/NzbDrone.Core.Test/ProviderTests/UpdateProviderTests/PreformUpdateFixture.cs index a6d09601d..1f31f0eb5 100644 --- a/NzbDrone.Core.Test/ProviderTests/UpdateProviderTests/PreformUpdateFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/UpdateProviderTests/PreformUpdateFixture.cs @@ -1,29 +1,34 @@ using System; using System.IO; -using AutoMoq; using FluentAssertions; -using Moq; using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Test.Framework; -using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider; namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests { [TestFixture] internal class PreformUpdateFixture : TestBase { - private AutoMoqer _mocker = null; + + private string SandBoxPath; [SetUp] public void setup() { - _mocker = new AutoMoqer(MockBehavior.Strict); - _mocker.GetMock() - .SetupGet(c => c.SystemTemp).Returns(TempFolder); + WithStrictMocker(); + Mocker.GetMock() + .SetupGet(c => c.UpdateSandboxFolder).Returns(Path.Combine(TempFolder, "NzbDrone_update")); + + + SandBoxPath = Mocker.GetMock().Object.UpdateSandboxFolder; + + Mocker.GetMock() + .SetupGet(c => c.UpdatePackageFolder).Returns(Path.Combine(SandBoxPath, "NzbDrone")); + } @@ -38,21 +43,20 @@ namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests Version = new Version("0.6.0.2031") }; - _mocker.GetMock().Setup( - c => c.DownloadFile(updatePackage.Url, Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME, updatePackage.FileName))); + Mocker.GetMock().Setup( + c => c.DownloadFile(updatePackage.Url, Path.Combine(SandBoxPath, updatePackage.FileName))); - _mocker.GetMock().Setup( - c => c.ExtractArchive(Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME, updatePackage.FileName), - Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME))); + Mocker.GetMock().Setup( + c => c.ExtractArchive(Path.Combine(SandBoxPath, updatePackage.FileName), SandBoxPath)); - _mocker.Resolve().PreformUpdate(updatePackage); + Mocker.Resolve().StartUpgrade(updatePackage); } [Test] public void Should_download_and_extract_to_temp_folder() { - var updateSubFolder = new DirectoryInfo(Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME)); + var updateSubFolder = new DirectoryInfo(SandBoxPath); var updatePackage = new UpdatePackage { @@ -65,9 +69,10 @@ namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests //Act updateSubFolder.Exists.Should().BeFalse(); - _mocker.Resolve(); - _mocker.Resolve(); - _mocker.Resolve().PreformUpdate(updatePackage); + Mocker.Resolve(); + Mocker.Resolve(); + Mocker.Resolve(); + Mocker.Resolve().StartUpgrade(updatePackage); updateSubFolder.Refresh(); //Assert diff --git a/NzbDrone.Core/Providers/Core/DiskProvider.cs b/NzbDrone.Core/Providers/Core/DiskProvider.cs index 4fe32a0f7..aa2de9abf 100644 --- a/NzbDrone.Core/Providers/Core/DiskProvider.cs +++ b/NzbDrone.Core/Providers/Core/DiskProvider.cs @@ -1,122 +1,25 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; +using System.Linq; using Ionic.Zip; using NLog; namespace NzbDrone.Core.Providers.Core { - public class DiskProvider + public class ArchiveProvider { - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, - out ulong lpFreeBytesAvailable, - out ulong lpTotalNumberOfBytes, - out ulong lpTotalNumberOfFreeBytes); - - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - public virtual bool FolderExists(string path) - { - return Directory.Exists(path); - } - - public virtual bool FileExists(string path) - { - return File.Exists(path); - } - - public virtual string[] GetDirectories(string path) - { - return Directory.GetDirectories(path); - } - - public virtual string[] GetFiles(string path, SearchOption searchOption) - { - return Directory.GetFiles(path, "*.*", searchOption); - } - - public virtual long GetDirectorySize(string path) - { - return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length); - } - - public virtual long GetSize(string path) - { - var fi = new FileInfo(path); - return fi.Length; - //return new FileInfo(path).Length; - } - - public virtual String CreateDirectory(string path) - { - return Directory.CreateDirectory(path).FullName; - } - - public virtual void DeleteFile(string path) - { - File.Delete(path); - } - - public virtual void MoveFile(string sourcePath, string destinationPath) - { - File.Move(sourcePath, destinationPath); - } - - public virtual void DeleteFolder(string path, bool recursive) - { - Directory.Delete(path, recursive); - } - - public virtual DateTime DirectoryDateCreated(string path) - { - return Directory.GetCreationTime(path); - } - - public virtual IEnumerable GetFileInfos(string path, string pattern, SearchOption searchOption) - { - return new DirectoryInfo(path).GetFiles(pattern, searchOption); - } - - public virtual void MoveDirectory(string source, string destination) - { - Directory.Move(source, destination); - } + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + public virtual void ExtractArchive(string compressedFile, string destination) { - Logger.Trace("Extracting archive [{0}] to [{1}]", compressedFile, destination); + logger.Trace("Extracting archive [{0}] to [{1}]", compressedFile, destination); using (ZipFile zipFile = ZipFile.Read(compressedFile)) { zipFile.ExtractAll(destination); } - Logger.Trace("Extraction complete."); + logger.Trace("Extraction complete."); } - public virtual void InheritFolderPermissions(string filename) - { - var fs = File.GetAccessControl(filename); - fs.SetAccessRuleProtection(false, false); - File.SetAccessControl(filename, fs); - } - - public virtual ulong FreeDiskSpace(DirectoryInfo directoryInfo) - { - ulong freeBytesAvailable; - ulong totalNumberOfBytes; - ulong totalNumberOfFreeBytes; - - bool success = GetDiskFreeSpaceEx(directoryInfo.FullName, out freeBytesAvailable, out totalNumberOfBytes, - out totalNumberOfFreeBytes); - if (!success) - throw new System.ComponentModel.Win32Exception(); - - return freeBytesAvailable; - } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index ddb848e4d..b9691a7e9 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using Ninject; using NLog; +using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; diff --git a/NzbDrone.Core/Providers/Jobs/BannerDownloadJob.cs b/NzbDrone.Core/Providers/Jobs/BannerDownloadJob.cs index f90e73748..7d3942e9c 100644 --- a/NzbDrone.Core/Providers/Jobs/BannerDownloadJob.cs +++ b/NzbDrone.Core/Providers/Jobs/BannerDownloadJob.cs @@ -8,7 +8,6 @@ using NzbDrone.Common; using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; -using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider; namespace NzbDrone.Core.Providers.Jobs { diff --git a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs index 8ace8bf40..bf21ac3f9 100644 --- a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs +++ b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs @@ -1,6 +1,7 @@ using System; using NLog; using Ninject; +using NzbDrone.Common; using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Providers.Core; diff --git a/NzbDrone.Core/Providers/PostDownloadProvider.cs b/NzbDrone.Core/Providers/PostDownloadProvider.cs index 439c87cf5..90330875c 100644 --- a/NzbDrone.Core/Providers/PostDownloadProvider.cs +++ b/NzbDrone.Core/Providers/PostDownloadProvider.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text.RegularExpressions; using NLog; using Ninject; +using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers.Core; diff --git a/NzbDrone.Core/Providers/RootDirProvider.cs b/NzbDrone.Core/Providers/RootDirProvider.cs index 4c4c804ef..98574b5c2 100644 --- a/NzbDrone.Core/Providers/RootDirProvider.cs +++ b/NzbDrone.Core/Providers/RootDirProvider.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using Ninject; using NLog; +using NzbDrone.Common; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; using PetaPoco; diff --git a/NzbDrone.Core/Providers/UpdateProvider.cs b/NzbDrone.Core/Providers/UpdateProvider.cs index dab67ad13..9bdb51104 100644 --- a/NzbDrone.Core/Providers/UpdateProvider.cs +++ b/NzbDrone.Core/Providers/UpdateProvider.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using NLog; using Ninject; using NzbDrone.Common; using NzbDrone.Core.Model; using NzbDrone.Core.Providers.Core; -using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider; + namespace NzbDrone.Core.Providers { @@ -20,6 +19,7 @@ namespace NzbDrone.Core.Providers private readonly EnviromentProvider _enviromentProvider; private readonly PathProvider _pathProvider; private readonly DiskProvider _diskProvider; + private readonly ArchiveProvider _archiveProvider; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Regex ParseRegex = new Regex(@"(?:\>)(?NzbDrone.+?(?\d+\.\d+\.\d+\.\d+).+?)(?:\<\/A\>)", RegexOptions.IgnoreCase); @@ -28,13 +28,14 @@ namespace NzbDrone.Core.Providers [Inject] public UpdateProvider(HttpProvider httpProvider, ConfigProvider configProvider, EnviromentProvider enviromentProvider, - PathProvider pathProvider, DiskProvider diskProvider) + PathProvider pathProvider, DiskProvider diskProvider, ArchiveProvider archiveProvider) { _httpProvider = httpProvider; _configProvider = configProvider; _enviromentProvider = enviromentProvider; _pathProvider = pathProvider; _diskProvider = diskProvider; + _archiveProvider = archiveProvider; } public UpdateProvider() @@ -74,7 +75,7 @@ namespace NzbDrone.Core.Providers return null; } - public virtual void PreformUpdate(UpdatePackage updatePackage) + public virtual void StartUpgrade(UpdatePackage updatePackage) { var packageDestination = Path.Combine(_pathProvider.UpdateSandboxFolder, updatePackage.FileName); @@ -83,7 +84,7 @@ namespace NzbDrone.Core.Providers Logger.Info("Download completed for update package from [{0}]", updatePackage.FileName); Logger.Info("Extracting Update package"); - _diskProvider.ExtractArchive(packageDestination, _pathProvider.UpdateSandboxFolder); + _archiveProvider.ExtractArchive(packageDestination, _pathProvider.UpdateSandboxFolder); Logger.Info("Update package extracted successfully"); } diff --git a/NzbDrone.Update.Test/UpdateProviderStartTest.cs b/NzbDrone.Update.Test/UpdateProviderStartTest.cs index 920f89a2f..6ac2d71fa 100644 --- a/NzbDrone.Update.Test/UpdateProviderStartTest.cs +++ b/NzbDrone.Update.Test/UpdateProviderStartTest.cs @@ -1,4 +1,5 @@ -using AutoMoq; +using System.IO; +using AutoMoq; using FizzWare.NBuilder; using Moq; using NUnit.Framework; @@ -13,21 +14,47 @@ namespace NzbDrone.Update.Test { AutoMoqer mocker = new AutoMoqer(); + private const string UPDATE_FOLDER = @"C:\Temp\NzbDrone_update\NzbDrone"; + private const string BACKUP_FOLDER = @"C:\Temp\NzbDrone_update\NzbDrone_Backup"; + private const string TARGET_FOLDER = @"C:\NzbDrone\"; + + Mock _pathProvider = null; + + [SetUp] public void Setup() { mocker = new AutoMoqer(); + + + _pathProvider = mocker.GetMock(); + + _pathProvider.SetupGet(c => c.UpdateBackUpFolder).Returns(BACKUP_FOLDER); + _pathProvider.SetupGet(c => c.UpdatePackageFolder).Returns(UPDATE_FOLDER); + + mocker.GetMock() + .Setup(c => c.FolderExists(UPDATE_FOLDER)) + .Returns(true); + + mocker.GetMock() + .Setup(c => c.FolderExists(TARGET_FOLDER)) + .Returns(true); + } + + public void WithInstalledService() + { + mocker.GetMock() + .Setup(c => c.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) + .Returns(true); } [Test] public void should_stop_nzbdrone_service_if_installed() { - mocker.GetMock() - .Setup(c => c.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) - .Returns(true); + WithInstalledService(); //Act - mocker.Resolve().Start(null); + mocker.Resolve().Start(TARGET_FOLDER); //Assert mocker.GetMock().Verify(c => c.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once()); @@ -44,12 +71,89 @@ namespace NzbDrone.Update.Test .Returns(proccesses); //Act - mocker.Resolve().Start(null); + mocker.Resolve().Start(TARGET_FOLDER); //Assert mocker.GetMock().Verify(c => c.Kill(proccesses[0].Id), Times.Once()); mocker.GetMock().Verify(c => c.Kill(proccesses[1].Id), Times.Once()); mocker.VerifyAllMocks(); } + + [Test] + public void should_create_backup_of_current_installation() + { + var diskprovider = mocker.GetMock() + .Setup(c => c.CopyDirectory(TARGET_FOLDER, BACKUP_FOLDER)); + + mocker.Resolve().Start(TARGET_FOLDER); + + mocker.VerifyAllMocks(); + } + + [Test] + public void should_copy_update_package_to_target() + { + var diskprovider = mocker.GetMock() + .Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER)); + + mocker.Resolve().Start(TARGET_FOLDER); + + mocker.VerifyAllMocks(); + } + + [Test] + public void should_restore_if_update_fails() + { + var diskprovider = mocker.GetMock(); + diskprovider.Setup(c => c.CopyDirectory(BACKUP_FOLDER, TARGET_FOLDER)); + + diskprovider.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER)).Throws(new IOException()); + + mocker.Resolve().Start(TARGET_FOLDER); + + mocker.VerifyAllMocks(); + } + + [Test] + public void should_restart_service_if_service_was_running() + { + WithInstalledService(); + + var serviceProvider = mocker.GetMock(); + + serviceProvider.Setup(c => c.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME)).Returns(true); + + //Act + mocker.Resolve().Start(TARGET_FOLDER); + + //Assert + serviceProvider + .Verify(c => c.Start(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once()); + + mocker.VerifyAllMocks(); + } + + [Test] + public void should_not_restart_service_if_service_was_not_running() + { + WithInstalledService(); + + var serviceProvider = mocker.GetMock(); + + serviceProvider.Setup(c => c.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME)) + .Returns(false); + + //Act + mocker.Resolve().Start(TARGET_FOLDER); + + //Assert + mocker.GetMock() + .Verify(c => c.Start(TARGET_FOLDER + "nzbdrone.exe"), Times.Once()); + + serviceProvider + .Verify(c => c.Start(It.IsAny()), Times.Never()); + + mocker.VerifyAllMocks(); + } } } diff --git a/NzbDrone.Update.Test/UpdateProviderVerifyTest.cs b/NzbDrone.Update.Test/UpdateProviderVerifyTest.cs index 1e4d833d2..e5b31dd59 100644 --- a/NzbDrone.Update.Test/UpdateProviderVerifyTest.cs +++ b/NzbDrone.Update.Test/UpdateProviderVerifyTest.cs @@ -28,25 +28,25 @@ namespace NzbDrone.Update.Test [TestCase(null)] [TestCase("")] [TestCase(" ")] - public void verify_should_throw_target_folder_is_blank(string target) + public void update_should_throw_target_folder_is_blank(string target) { - Assert.Throws(() => mocker.Resolve().Verify(target)) + Assert.Throws(() => mocker.Resolve().Start(target)) .Message.Should().StartWith("Target folder can not be null or empty"); } [Test] - public void verify_should_throw_if_target_folder_doesnt_exist() + public void update_should_throw_if_target_folder_doesnt_exist() { string targetFolder = "c:\\NzbDrone\\"; - Assert.Throws(() => mocker.Resolve().Verify(targetFolder)) + Assert.Throws(() => mocker.Resolve().Start(targetFolder)) .Message.Should().StartWith("Target folder doesn't exist"); } [Test] - public void verify_should_throw_if_update_folder_doesnt_exist() + public void update_should_throw_if_update_folder_doesnt_exist() { - const string sandboxFolder = @"C:\Temp\NzbDrone_update\nzbdrone_update"; + const string sandboxFolder = @"C:\Temp\NzbDrone_update\nzbdrone"; const string targetFolder = "c:\\NzbDrone\\"; mocker.GetMock() @@ -57,22 +57,8 @@ namespace NzbDrone.Update.Test .Setup(c => c.FolderExists(sandboxFolder)) .Returns(false); - Assert.Throws(() => mocker.Resolve().Verify(targetFolder)) + Assert.Throws(() => mocker.Resolve().Start(targetFolder)) .Message.Should().StartWith("Update folder doesn't exist"); } - - [Test] - public void verify_should_pass_if_update_folder_and_target_folder_both_exist() - { - const string targetFolder = "c:\\NzbDrone\\"; - - mocker.GetMock() - .Setup(c => c.FolderExists(It.IsAny())) - .Returns(true); - - mocker.Resolve().Verify(targetFolder); - - mocker.VerifyAllMocks(); - } } } diff --git a/NzbDrone.Update/Providers/UpdateProvider.cs b/NzbDrone.Update/Providers/UpdateProvider.cs index b92f2d302..69aa02e6f 100644 --- a/NzbDrone.Update/Providers/UpdateProvider.cs +++ b/NzbDrone.Update/Providers/UpdateProvider.cs @@ -12,40 +12,47 @@ namespace NzbDrone.Update.Providers private readonly EnviromentProvider _enviromentProvider; private readonly ServiceProvider _serviceProvider; private readonly ProcessProvider _processProvider; + private readonly PathProvider _pathProvider; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public UpdateProvider(DiskProvider diskProvider, EnviromentProvider enviromentProvider, - ServiceProvider serviceProvider, ProcessProvider processProvider) + ServiceProvider serviceProvider, ProcessProvider processProvider, PathProvider pathProvider) { _diskProvider = diskProvider; _enviromentProvider = enviromentProvider; _serviceProvider = serviceProvider; _processProvider = processProvider; + _pathProvider = pathProvider; } - public void Verify(string targetFolder) + private void Verify(string installationFolder) { Logger.Info("Verifying requirements before update..."); - if (String.IsNullOrWhiteSpace(targetFolder)) + if (String.IsNullOrWhiteSpace(installationFolder)) throw new ArgumentException("Target folder can not be null or empty"); - if (!_diskProvider.FolderExists(targetFolder)) - throw new DirectoryNotFoundException("Target folder doesn't exist" + targetFolder); - - var sandboxFolder = Path.Combine(_enviromentProvider.StartUpPath, "nzbdrone_update"); + if (!_diskProvider.FolderExists(installationFolder)) + throw new DirectoryNotFoundException("Target folder doesn't exist" + installationFolder); Logger.Info("Verifying Update Folder"); - if (!_diskProvider.FolderExists(sandboxFolder)) - throw new DirectoryNotFoundException("Update folder doesn't exist" + sandboxFolder); + if (!_diskProvider.FolderExists(_pathProvider.UpdatePackageFolder)) + throw new DirectoryNotFoundException("Update folder doesn't exist" + _pathProvider.UpdateSandboxFolder); } - public void Start(string installationFolder) + public void Start(string targetFolder) { + Verify(targetFolder); + bool isService = false; + Logger.Info("Stopping all running services"); if (_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) { + if (_serviceProvider.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME)) + { + isService = true; + } _serviceProvider.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME); } @@ -56,17 +63,44 @@ namespace NzbDrone.Update.Providers _processProvider.Kill(processInfo.Id); } + Logger.Info("Creating backup of existing installation"); + _diskProvider.CopyDirectory(targetFolder, _pathProvider.UpdateBackUpFolder); - //Create backup of current folder - //Copy update folder on top of the existing folder + Logger.Info("Copying update package to target"); - //Happy: Cleanup - //Happy: Start Service, Process? + try + { + _diskProvider.CopyDirectory(_pathProvider.UpdatePackageFolder, targetFolder); + } + catch (Exception e) + { + RollBack(targetFolder); + Logger.Fatal("Failed to copy upgrade package to target folder.", e); + } + finally + { + StartNzbDrone(isService, targetFolder); + } + } - //Sad: delete fucked up folder - //Sad: restore backup - //Sad: start service, process + private void RollBack(string targetFolder) + { + Logger.Info("Attempting to rollback upgrade"); + _diskProvider.CopyDirectory(_pathProvider.UpdateBackUpFolder, targetFolder); + } + + + private void StartNzbDrone(bool isService, string targetFolder) + { + if (isService) + { + _serviceProvider.Start(ServiceProvider.NZBDRONE_SERVICE_NAME); + } + else + { + _processProvider.Start(Path.Combine(targetFolder, "nzbdrone.exe")); + } } } } diff --git a/NzbDrone.Web/Controllers/AddSeriesController.cs b/NzbDrone.Web/Controllers/AddSeriesController.cs index 0487b540f..5449da36b 100644 --- a/NzbDrone.Web/Controllers/AddSeriesController.cs +++ b/NzbDrone.Web/Controllers/AddSeriesController.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Web.Mvc; using NLog; +using NzbDrone.Common; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Jobs; diff --git a/NzbDrone.Web/Controllers/DirectoryController.cs b/NzbDrone.Web/Controllers/DirectoryController.cs index ee87dc1b0..faae59850 100644 --- a/NzbDrone.Web/Controllers/DirectoryController.cs +++ b/NzbDrone.Web/Controllers/DirectoryController.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.Helpers; -using System.Web.Mvc; -using NzbDrone.Core.Providers.Core; +using System.Web.Mvc; +using NzbDrone.Common; namespace NzbDrone.Web.Controllers { diff --git a/NzbDrone.Web/Controllers/SystemController.cs b/NzbDrone.Web/Controllers/SystemController.cs index c247c77fd..569e98a63 100644 --- a/NzbDrone.Web/Controllers/SystemController.cs +++ b/NzbDrone.Web/Controllers/SystemController.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Web.Mvc; +using NzbDrone.Common; using NzbDrone.Core.Helpers; -using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Jobs;