From ef3777fccf2c0e975f1cf5342ef64bbbfcd485f6 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 27 Apr 2014 23:34:29 -0700 Subject: [PATCH] Update improvements Include NzbDrone.Update in mono/osx package Do not ignore certificate warnings for services Check hash before extracting update New: Update support for Linux/OS X - see the wiki for more information --- build.ps1 | 7 +- src/NzbDrone.Api/Config/HostConfigModule.cs | 6 +- src/NzbDrone.Api/Config/HostConfigResource.cs | 5 +- src/NzbDrone.Api/NzbDrone.Api.csproj | 1 + src/NzbDrone.Api/Update/UpdateModule.cs | 19 +--- src/NzbDrone.Api/Update/UpdateResource.cs | 22 +++++ .../NzbDroneProcessServiceFixture.cs | 53 ++++++----- .../PathExtensionFixture.cs | 8 +- src/NzbDrone.Common/Disk/DiskProviderBase.cs | 10 ++ src/NzbDrone.Common/Disk/IDiskProvider.cs | 2 +- .../EnvironmentInfo/StartupContext.cs | 4 +- src/NzbDrone.Common/NzbDrone.Common.csproj | 1 - src/NzbDrone.Common/PathExtensions.cs | 4 +- .../Processes/INzbDroneProcessProvider.cs | 10 -- .../Processes/ProcessProvider.cs | 76 +++++++++------- .../Properties/AssemblyInfo.cs | 2 +- .../Security/IgnoreCertErrorPolicy.cs | 9 ++ src/NzbDrone.Common/StringExtensions.cs | 16 ++++ .../UpdateTests/UpdateServiceFixture.cs | 91 ++++++++++++++++++- .../Configuration/ConfigFileProvider.cs | 31 +++++-- .../Configuration/ConfigService.cs | 1 + .../Configuration/IConfigService.cs | 2 +- src/NzbDrone.Core/NzbDrone.Core.csproj | 3 + src/NzbDrone.Core/Security.cs | 28 ++++-- .../Update/InstallUpdateService.cs | 65 ++++++++++++- .../Update/UpdateCheckService.cs | 9 +- src/NzbDrone.Core/Update/UpdateMechanism.cs | 8 ++ src/NzbDrone.Core/Update/UpdatePackage.cs | 1 + .../Update/UpdateVerification.cs | 30 ++++++ .../UpdateVerificationFailedException.cs | 15 +++ src/NzbDrone.Host/SingleInstancePolicy.cs | 12 +-- src/NzbDrone.Mono/NzbDrone.Mono.csproj | 1 - src/NzbDrone.Mono/NzbDroneProcessProvider.cs | 43 --------- src/NzbDrone.Test.Common/LoggingTest.cs | 2 +- src/NzbDrone.Test.Dummy/DummyApp.cs | 4 +- src/NzbDrone.Update/NzbDrone.Update.csproj | 1 + src/NzbDrone.Update/UpdateApp.cs | 54 +++++++++-- .../UpdateEngine/DetectApplicationType.cs | 7 ++ .../UpdateEngine/InstallUpdateService.cs | 1 - .../UpdateEngine/TerminateNzbDrone.cs | 11 ++- src/NzbDrone.Update/UpdateStartupContext.cs | 11 +++ src/NzbDrone.Windows/NzbDrone.Windows.csproj | 1 - .../NzbDroneProcessProvider.cs | 25 ----- src/UI/Settings/General/GeneralView.js | 44 ++++++--- .../Settings/General/GeneralViewTemplate.html | 73 ++++++++++----- .../System/Update/UpdateItemViewTemplate.html | 14 +-- 46 files changed, 588 insertions(+), 255 deletions(-) create mode 100644 src/NzbDrone.Api/Update/UpdateResource.cs delete mode 100644 src/NzbDrone.Common/Processes/INzbDroneProcessProvider.cs create mode 100644 src/NzbDrone.Core/Update/UpdateMechanism.cs create mode 100644 src/NzbDrone.Core/Update/UpdateVerification.cs create mode 100644 src/NzbDrone.Core/Update/UpdateVerificationFailedException.cs delete mode 100644 src/NzbDrone.Mono/NzbDroneProcessProvider.cs create mode 100644 src/NzbDrone.Update/UpdateStartupContext.cs delete mode 100644 src/NzbDrone.Windows/NzbDroneProcessProvider.cs diff --git a/build.ps1 b/build.ps1 index 69b85fcfe..0a20c3af3 100644 --- a/build.ps1 +++ b/build.ps1 @@ -6,6 +6,7 @@ $testPackageFolder = '.\_tests\' $testSearchPattern = '*.Test\bin\x86\Release' $sourceFolder = '.\src' $updateFolder = $outputFolder + '\NzbDrone.Update' +$updateFolderMono = $outputFolderMono + '\NzbDrone.Update' Function Build() { @@ -73,9 +74,6 @@ Function PackageMono() Copy-Item $outputFolder $outputFolderMono -recurse - Write-Host Removing Update Client - Remove-Item -Recurse -Force "$outputFolderMono\NzbDrone.Update" - Write-Host Creating MDBs get-childitem $outputFolderMono -File -Include @("*.exe", "*.dll") -Exclude @("MediaInfo.dll", "sqlite3.dll") -Recurse | foreach ($_) { Write-Host "Creating .mdb for $_" @@ -110,6 +108,9 @@ Function PackageMono() Remove-Item "$outputFolderMono\NzbDrone.Console.vshost.exe" + Write-Host Adding NzbDrone.Mono to UpdatePackage + Copy-Item $outputFolderMono\* $updateFolderMono -Filter NzbDrone.Mono.* + Write-Host "##teamcity[progressFinish 'Creating Mono Package']" } diff --git a/src/NzbDrone.Api/Config/HostConfigModule.cs b/src/NzbDrone.Api/Config/HostConfigModule.cs index 26c184c45..1c9d37aa7 100644 --- a/src/NzbDrone.Api/Config/HostConfigModule.cs +++ b/src/NzbDrone.Api/Config/HostConfigModule.cs @@ -3,7 +3,9 @@ using FluentValidation; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Update; using NzbDrone.Core.Validation; +using NzbDrone.Core.Validation.Paths; using Omu.ValueInjecter; namespace NzbDrone.Api.Config @@ -12,7 +14,7 @@ public class HostConfigModule : NzbDroneRestModule { private readonly IConfigFileProvider _configFileProvider; - public HostConfigModule(ConfigFileProvider configFileProvider) + public HostConfigModule(IConfigFileProvider configFileProvider) : base("/config/host") { _configFileProvider = configFileProvider; @@ -29,6 +31,8 @@ public HostConfigModule(ConfigFileProvider configFileProvider) SharedValidator.RuleFor(c => c.SslPort).ValidPort().When(c => c.EnableSsl); SharedValidator.RuleFor(c => c.SslCertHash).NotEmpty().When(c => c.EnableSsl && OsInfo.IsWindows); + + SharedValidator.RuleFor(c => c.UpdateScriptPath).IsValidPath().When(c => c.UpdateMechanism == UpdateMechanism.Script); } private HostConfigResource GetHostConfig() diff --git a/src/NzbDrone.Api/Config/HostConfigResource.cs b/src/NzbDrone.Api/Config/HostConfigResource.cs index 3387ba421..cc52c01c4 100644 --- a/src/NzbDrone.Api/Config/HostConfigResource.cs +++ b/src/NzbDrone.Api/Config/HostConfigResource.cs @@ -1,5 +1,6 @@ using System; using NzbDrone.Api.REST; +using NzbDrone.Core.Update; namespace NzbDrone.Api.Config { @@ -14,10 +15,12 @@ public class HostConfigResource : RestResource public String Password { get; set; } public String LogLevel { get; set; } public String Branch { get; set; } - public Boolean AutoUpdate { get; set; } public String ApiKey { get; set; } public Boolean Torrent { get; set; } public String SslCertHash { get; set; } public String UrlBase { get; set; } + public Boolean UpdateAutomatically { get; set; } + public UpdateMechanism UpdateMechanism { get; set; } + public String UpdateScriptPath { get; set; } } } diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index 9c7f11503..da8ffac05 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -162,6 +162,7 @@ + diff --git a/src/NzbDrone.Api/Update/UpdateModule.cs b/src/NzbDrone.Api/Update/UpdateModule.cs index 02696a9b8..959dd0d7c 100644 --- a/src/NzbDrone.Api/Update/UpdateModule.cs +++ b/src/NzbDrone.Api/Update/UpdateModule.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; -using NzbDrone.Api.REST; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Update; using NzbDrone.Api.Mapping; @@ -44,18 +41,4 @@ private List GetRecentUpdates() return resources; } } - - public class UpdateResource : RestResource - { - [JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))] - public Version Version { get; set; } - - public String Branch { get; set; } - public DateTime ReleaseDate { get; set; } - public String FileName { get; set; } - public String Url { get; set; } - public Boolean IsUpgrade { get; set; } - public Boolean Installed { get; set; } - public UpdateChanges Changes { get; set; } - } } \ No newline at end of file diff --git a/src/NzbDrone.Api/Update/UpdateResource.cs b/src/NzbDrone.Api/Update/UpdateResource.cs new file mode 100644 index 000000000..c12edfbc1 --- /dev/null +++ b/src/NzbDrone.Api/Update/UpdateResource.cs @@ -0,0 +1,22 @@ +using System; +using Newtonsoft.Json; +using NzbDrone.Api.REST; +using NzbDrone.Core.Update; + +namespace NzbDrone.Api.Update +{ + public class UpdateResource : RestResource + { + [JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))] + public Version Version { get; set; } + + public String Branch { get; set; } + public DateTime ReleaseDate { get; set; } + public String FileName { get; set; } + public String Url { get; set; } + public Boolean IsUpgrade { get; set; } + public Boolean Installed { get; set; } + public UpdateChanges Changes { get; set; } + public String Hash { get; set; } + } +} diff --git a/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs b/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs index faef69f54..63693a88f 100644 --- a/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs +++ b/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Moq; using NUnit.Framework; using NzbDrone.Common.Model; @@ -18,17 +19,25 @@ public void Setup() { Mocker.GetMock().Setup(c => c.GetCurrentProcess()) .Returns(new ProcessInfo() { Id = CURRENT_PROCESS_ID }); + + Mocker.GetMock() + .Setup(s => s.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME)) + .Returns(new List()); + + Mocker.GetMock() + .Setup(s => s.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME)) + .Returns(new List()); } [Test] public void should_continue_if_only_instance() { - Mocker.GetMock().Setup(c => c.FindNzbDroneProcesses()) - .Returns(new List - { - new ProcessInfo{Id = CURRENT_PROCESS_ID} - }); - + Mocker.GetMock() + .Setup(c => c.FindProcessByName(It.Is(f => f.Contains("NzbDrone")))) + .Returns(new List + { + new ProcessInfo {Id = CURRENT_PROCESS_ID} + }); Subject.PreventStartIfAlreadyRunning(); @@ -38,13 +47,13 @@ public void should_continue_if_only_instance() [Test] public void should_enforce_if_another_console_is_running() { - Mocker.GetMock() - .Setup(c => c.FindNzbDroneProcesses()) - .Returns(new List - { - new ProcessInfo{Id = 10}, - new ProcessInfo{Id = CURRENT_PROCESS_ID} - }); + Mocker.GetMock() + .Setup(c => c.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME)) + .Returns(new List + { + new ProcessInfo {Id = 10}, + new ProcessInfo {Id = CURRENT_PROCESS_ID} + }); Assert.Throws(() => Subject.PreventStartIfAlreadyRunning()); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Once()); @@ -54,14 +63,14 @@ public void should_enforce_if_another_console_is_running() [Test] public void should_return_false_if_another_gui_is_running() { - Mocker.GetMock() - .Setup(c => c.FindNzbDroneProcesses()) - .Returns(new List - { - new ProcessInfo{Id = CURRENT_PROCESS_ID}, - new ProcessInfo{Id = 10} - - }); + Mocker.GetMock() + .Setup(c => c.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME)) + .Returns(new List + { + new ProcessInfo {Id = CURRENT_PROCESS_ID}, + new ProcessInfo {Id = 10} + + }); Assert.Throws(() => Subject.PreventStartIfAlreadyRunning()); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Once()); diff --git a/src/NzbDrone.Common.Test/PathExtensionFixture.cs b/src/NzbDrone.Common.Test/PathExtensionFixture.cs index 4dd274a33..fd59e7eec 100644 --- a/src/NzbDrone.Common.Test/PathExtensionFixture.cs +++ b/src/NzbDrone.Common.Test/PathExtensionFixture.cs @@ -168,25 +168,25 @@ public void Config_path_test() [Test] public void Sanbox() { - GetIAppDirectoryInfo().GetUpdateSandboxFolder().Should().BeEquivalentTo(@"C:\Temp\Nzbdrone_update\".AsOsAgnostic()); + GetIAppDirectoryInfo().GetUpdateSandboxFolder().Should().BeEquivalentTo(@"C:\Temp\nzbdrone_update\".AsOsAgnostic()); } [Test] public void GetUpdatePackageFolder() { - GetIAppDirectoryInfo().GetUpdatePackageFolder().Should().BeEquivalentTo(@"C:\Temp\Nzbdrone_update\NzbDrone\".AsOsAgnostic()); + GetIAppDirectoryInfo().GetUpdatePackageFolder().Should().BeEquivalentTo(@"C:\Temp\nzbdrone_update\NzbDrone\".AsOsAgnostic()); } [Test] public void GetUpdateClientFolder() { - GetIAppDirectoryInfo().GetUpdateClientFolder().Should().BeEquivalentTo(@"C:\Temp\Nzbdrone_update\NzbDrone\NzbDrone.Update\".AsOsAgnostic()); + GetIAppDirectoryInfo().GetUpdateClientFolder().Should().BeEquivalentTo(@"C:\Temp\nzbdrone_update\NzbDrone\NzbDrone.Update\".AsOsAgnostic()); } [Test] public void GetUpdateClientExePath() { - GetIAppDirectoryInfo().GetUpdateClientExePath().Should().BeEquivalentTo(@"C:\Temp\Nzbdrone_update\NzbDrone.Update.exe".AsOsAgnostic()); + GetIAppDirectoryInfo().GetUpdateClientExePath().Should().BeEquivalentTo(@"C:\Temp\nzbdrone_update\NzbDrone.Update.exe".AsOsAgnostic()); } [Test] diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index c2c4d0075..47a14be5c 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -447,5 +447,15 @@ public string GetVolumeLabel(string path) return driveInfo.VolumeLabel; } + + public FileStream StreamFile(string path) + { + if (!FileExists(path)) + { + throw new FileNotFoundException("Unable to find file: " + path, path); + } + + return new FileStream(path, FileMode.Open); + } } } diff --git a/src/NzbDrone.Common/Disk/IDiskProvider.cs b/src/NzbDrone.Common/Disk/IDiskProvider.cs index 896f393bb..b57486ff9 100644 --- a/src/NzbDrone.Common/Disk/IDiskProvider.cs +++ b/src/NzbDrone.Common/Disk/IDiskProvider.cs @@ -11,7 +11,6 @@ public interface IDiskProvider void InheritFolderPermissions(string filename); void SetPermissions(string path, string mask, string user, string group); long? GetTotalSize(string path); - DateTime FolderGetLastWrite(string path); DateTime FileGetLastWrite(string path); DateTime FileGetLastWriteUtc(string path); @@ -44,5 +43,6 @@ public interface IDiskProvider void EmptyFolder(string path); string[] GetFixedDrives(); string GetVolumeLabel(string path); + FileStream StreamFile(string path); } } \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs b/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs index dbf4e6d65..1e21eeb48 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Text; namespace NzbDrone.Common.EnvironmentInfo { diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index 6520ff59d..e0a90c375 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -105,7 +105,6 @@ - diff --git a/src/NzbDrone.Common/PathExtensions.cs b/src/NzbDrone.Common/PathExtensions.cs index 16a9bddd1..a5c171039 100644 --- a/src/NzbDrone.Common/PathExtensions.cs +++ b/src/NzbDrone.Common/PathExtensions.cs @@ -13,10 +13,10 @@ public static class PathExtensions private const string NZBDRONE_LOG_DB = "logs.db"; private const string BACKUP_ZIP_FILE = "NzbDrone_Backup.zip"; private const string NLOG_CONFIG_FILE = "nlog.config"; - private const string UPDATE_CLIENT_EXE = "nzbdrone.update.exe"; + private const string UPDATE_CLIENT_EXE = "NzbDrone.Update.exe"; private static readonly string UPDATE_SANDBOX_FOLDER_NAME = "nzbdrone_update" + Path.DirectorySeparatorChar; - private static readonly string UPDATE_PACKAGE_FOLDER_NAME = "nzbdrone" + Path.DirectorySeparatorChar; + private static readonly string UPDATE_PACKAGE_FOLDER_NAME = "NzbDrone" + Path.DirectorySeparatorChar; private static readonly string UPDATE_BACKUP_FOLDER_NAME = "nzbdrone_backup" + Path.DirectorySeparatorChar; private static readonly string UPDATE_BACKUP_APPDATA_FOLDER_NAME = "nzbdrone_appdata_backup" + Path.DirectorySeparatorChar; private static readonly string UPDATE_CLIENT_FOLDER_NAME = "NzbDrone.Update" + Path.DirectorySeparatorChar; diff --git a/src/NzbDrone.Common/Processes/INzbDroneProcessProvider.cs b/src/NzbDrone.Common/Processes/INzbDroneProcessProvider.cs deleted file mode 100644 index 71abd6d0e..000000000 --- a/src/NzbDrone.Common/Processes/INzbDroneProcessProvider.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using NzbDrone.Common.Model; - -namespace NzbDrone.Common.Processes -{ - public interface INzbDroneProcessProvider - { - List FindNzbDroneProcesses(); - } -} diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs index 7581a4b5c..6e9d2c0db 100644 --- a/src/NzbDrone.Common/Processes/ProcessProvider.cs +++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs @@ -21,7 +21,7 @@ public interface IProcessProvider void SetPriority(int processId, ProcessPriorityClass priority); void KillAll(string processName); void Kill(int processId); - bool Exists(string processName); + Boolean Exists(string processName); ProcessPriorityClass GetCurrentProcessPriority(); Process Start(string path, string args = null, Action onOutputDataReceived = null, Action onErrorDataReceived = null); Process SpawnNewProcess(string path, string args = null); @@ -35,20 +35,12 @@ public class ProcessProvider : IProcessProvider public const string NZB_DRONE_PROCESS_NAME = "NzbDrone"; public const string NZB_DRONE_CONSOLE_PROCESS_NAME = "NzbDrone.Console"; - private static List GetProcessesByName(string name) - { - var monoProcesses = Process.GetProcessesByName("mono") - .Where(process => process.Modules.Cast().Any(module => module.ModuleName.ToLower() == name.ToLower() + ".exe")); - return Process.GetProcessesByName(name) - .Union(monoProcesses).ToList(); - } - public ProcessInfo GetCurrentProcess() { return ConvertToProcessInfo(Process.GetCurrentProcess()); } - public bool Exists(string processName) + public Boolean Exists(string processName) { return GetProcessesByName(processName).Any(); } @@ -78,7 +70,7 @@ public ProcessInfo GetProcessById(int id) public List FindProcessByName(string name) { - return Process.GetProcessesByName(name).Select(ConvertToProcessInfo).Where(c => c != null).ToList(); + return GetProcessesByName(name).Select(ConvertToProcessInfo).Where(c => c != null).ToList(); } public void OpenDefaultBrowser(string url) @@ -203,12 +195,40 @@ public void SetPriority(int processId, ProcessPriorityClass priority) process.PriorityClass = priority; } + public void Kill(int processId) + { + var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId); + + if (process == null) + { + Logger.Warn("Cannot find process with id: {0}", processId); + return; + } + + process.Refresh(); + + if (process.HasExited) + { + Logger.Debug("Process has already exited"); + return; + } + + Logger.Info("[{0}]: Killing process", process.Id); + process.Kill(); + Logger.Info("[{0}]: Waiting for exit", process.Id); + process.WaitForExit(); + Logger.Info("[{0}]: Process terminated successfully", process.Id); + } + public void KillAll(string processName) { - var processToKill = GetProcessesByName(processName); + var processes = GetProcessesByName(processName); - foreach (var processInfo in processToKill) + Logger.Debug("Found {0} processes to kill", processes.Count); + + foreach (var processInfo in processes) { + Logger.Debug("Killing process: {0} [{1}]", processInfo.Id, processInfo.ProcessName); Kill(processInfo.Id); } } @@ -254,29 +274,23 @@ private static string GetExeFileName(Process process) return process.Modules.Cast().FirstOrDefault(module => module.ModuleName.ToLower().EndsWith(".exe")).FileName; } - public void Kill(int processId) + private static List GetProcessesByName(string name) { - var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId); + //TODO: move this to an OS specific class - if (process == null) - { - Logger.Warn("Cannot find process with id: {0}", processId); - return; - } + var monoProcesses = Process.GetProcessesByName("mono") + .Union(Process.GetProcessesByName("mono-sgen")) + .Where(process => + process.Modules.Cast() + .Any(module => + module.ModuleName.ToLower() == name.ToLower() + ".exe")); - process.Refresh(); + var processes = Process.GetProcessesByName(name) + .Union(monoProcesses).ToList(); - if (process.HasExited) - { - Logger.Debug("Process has already exited"); - return; - } + Logger.Debug("Found {0} processes with the name: {1}", processes.Count, name); - Logger.Info("[{0}]: Killing process", process.Id); - process.Kill(); - Logger.Info("[{0}]: Waiting for exit", process.Id); - process.WaitForExit(); - Logger.Info("[{0}]: Process terminated successfully", process.Id); + return processes; } } } diff --git a/src/NzbDrone.Common/Properties/AssemblyInfo.cs b/src/NzbDrone.Common/Properties/AssemblyInfo.cs index e9f498cc8..71f440bc5 100644 --- a/src/NzbDrone.Common/Properties/AssemblyInfo.cs +++ b/src/NzbDrone.Common/Properties/AssemblyInfo.cs @@ -12,5 +12,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("10.0.0.*")] +[assembly: AssemblyVersion("2.0.0.1")] [assembly: AssemblyFileVersion("10.0.0.*")] diff --git a/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs b/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs index 8e09b8024..604d357ba 100644 --- a/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs +++ b/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs @@ -13,6 +13,15 @@ public static void Register() private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors) { + var request = sender as HttpWebRequest; + + if (request != null && + request.Address.OriginalString.ContainsIgnoreCase("nzbdrone.com") && + sslpolicyerrors != SslPolicyErrors.None) + { + return false; + } + return true; } } diff --git a/src/NzbDrone.Common/StringExtensions.cs b/src/NzbDrone.Common/StringExtensions.cs index 21b1db970..77a6c9532 100644 --- a/src/NzbDrone.Common/StringExtensions.cs +++ b/src/NzbDrone.Common/StringExtensions.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; +using ICSharpCode.SharpZipLib.Zip; namespace NzbDrone.Common { @@ -65,5 +66,20 @@ public static bool IsNullOrWhiteSpace(this string text) { return String.IsNullOrWhiteSpace(text); } + + public static bool ContainsIgnoreCase(this string text, string contains) + { + return text.IndexOf(contains, StringComparison.InvariantCultureIgnoreCase) > -1; + } + + public static string WrapInQuotes(this string text) + { + if (!text.Contains(" ")) + { + return text; + } + + return "\"" + text + "\""; + } } } \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs index 85e5c872a..e01a08761 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs @@ -9,6 +9,7 @@ using NzbDrone.Common.Http; using NzbDrone.Common.Model; using NzbDrone.Common.Processes; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Update; using NzbDrone.Core.Update.Commands; @@ -49,12 +50,28 @@ public void Setup() Mocker.GetMock().SetupGet(c => c.TempFolder).Returns(TempFolder); Mocker.GetMock().Setup(c => c.AvailableUpdate()).Returns(_updatePackage); + Mocker.GetMock().Setup(c => c.Verify(It.IsAny(), It.IsAny())).Returns(true); Mocker.GetMock().Setup(c => c.GetCurrentProcess()).Returns(new ProcessInfo { Id = 12 }); + Mocker.GetMock().Setup(c => c.ExecutingApplication).Returns(@"C:\Test\NzbDrone.exe"); _sandboxFolder = Mocker.GetMock().Object.GetUpdateSandboxFolder(); } + private void GivenInstallScript(string path) + { + Mocker.GetMock() + .SetupGet(s => s.UpdateMechanism) + .Returns(UpdateMechanism.Script); + + Mocker.GetMock() + .SetupGet(s => s.UpdateScriptPath) + .Returns(path); + + Mocker.GetMock() + .Setup(s => s.FileExists(path, true)) + .Returns(true); + } [Test] public void should_delete_sandbox_before_update_if_folder_exists() @@ -77,7 +94,6 @@ public void should_not_delete_sandbox_before_update_if_folder_doesnt_exists() Mocker.GetMock().Verify(c => c.DeleteFolder(_sandboxFolder, true), Times.Never()); } - [Test] public void Should_download_update_package() { @@ -118,11 +134,11 @@ public void should_start_update_client() Subject.Execute(new ApplicationUpdateCommand()); Mocker.GetMock() - .Verify(c => c.Start(It.IsAny(), "12", null, null), Times.Once()); + .Verify(c => c.Start(It.IsAny(), It.Is(s => s.StartsWith("12")), null, null), Times.Once()); } [Test] - public void when_no_updates_are_available_should_return_without_error_or_warnings() + public void should_return_without_error_or_warnings_when_no_updates_are_available() { Mocker.GetMock().Setup(c => c.AvailableUpdate()).Returns(null); @@ -132,6 +148,75 @@ public void when_no_updates_are_available_should_return_without_error_or_warning ExceptionVerification.AssertNoUnexpectedLogs(); } + [Test] + public void should_not_extract_if_verification_fails() + { + Mocker.GetMock().Setup(c => c.Verify(It.IsAny(), It.IsAny())).Returns(false); + + Subject.Execute(new ApplicationUpdateCommand()); + + Mocker.GetMock().Verify(v => v.Extract(It.IsAny(), It.IsAny()), Times.Never()); + } + + [Test] + [Platform("Mono")] + public void should_run_script_if_configured() + { + const string scriptPath = "/tmp/nzbdrone/update.sh"; + + GivenInstallScript(scriptPath); + + Subject.Execute(new ApplicationUpdateCommand()); + + Mocker.GetMock().Verify(v => v.Start(scriptPath, It.IsAny(), null, null), Times.Once()); + } + + [Test] + [Platform("Mono")] + public void should_throw_if_script_is_not_set() + { + const string scriptPath = "/tmp/nzbdrone/update.sh"; + + GivenInstallScript(""); + + Subject.Execute(new ApplicationUpdateCommand()); + + ExceptionVerification.ExpectedErrors(1); + Mocker.GetMock().Verify(v => v.Start(scriptPath, It.IsAny(), null, null), Times.Never()); + } + + [Test] + [Platform("Mono")] + public void should_throw_if_script_is_null() + { + const string scriptPath = "/tmp/nzbdrone/update.sh"; + + GivenInstallScript(null); + + Subject.Execute(new ApplicationUpdateCommand()); + + ExceptionVerification.ExpectedErrors(1); + Mocker.GetMock().Verify(v => v.Start(scriptPath, It.IsAny(), null, null), Times.Never()); + } + + [Test] + [Platform("Mono")] + public void should_throw_if_script_path_does_not_exist() + { + const string scriptPath = "/tmp/nzbdrone/update.sh"; + + GivenInstallScript(scriptPath); + + Mocker.GetMock() + .Setup(s => s.FileExists(scriptPath, true)) + .Returns(false); + + Subject.Execute(new ApplicationUpdateCommand()); + + ExceptionVerification.ExpectedErrors(1); + Mocker.GetMock().Verify(v => v.Start(scriptPath, It.IsAny(), null, null), Times.Never()); + } + [Test] [IntegrationTest] public void Should_download_and_extract_to_temp_folder() diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index ef9c5e4dd..d0954c221 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Update; namespace NzbDrone.Core.Configuration @@ -30,11 +31,13 @@ public interface IConfigFileProvider : IHandleAsync, string Password { get; } string LogLevel { get; } string Branch { get; } - bool AutoUpdate { get; } string ApiKey { get; } bool Torrent { get; } string SslCertHash { get; } string UrlBase { get; } + Boolean UpdateAutomatically { get; } + UpdateMechanism UpdateMechanism { get; } + String UpdateScriptPath { get; } } public class ConfigFileProvider : IConfigFileProvider @@ -141,11 +144,6 @@ public string Branch get { return GetValue("Branch", "master").ToLowerInvariant(); } } - public bool AutoUpdate - { - get { return GetValueBoolean("AutoUpdate", false, persist: false); } - } - public string Username { get { return GetValue("Username", ""); } @@ -181,6 +179,21 @@ public string UrlBase } } + public bool UpdateAutomatically + { + get { return GetValueBoolean("UpdateAutomatically", false, false); } + } + + public UpdateMechanism UpdateMechanism + { + get { return GetValueEnum("UpdateMechanism", UpdateMechanism.BuiltIn, false); } + } + + public string UpdateScriptPath + { + get { return GetValue("UpdateScriptPath", "", false ); } + } + public int GetValueInt(string key, int defaultValue) { return Convert.ToInt32(GetValue(key, defaultValue)); @@ -191,9 +204,9 @@ public bool GetValueBoolean(string key, bool defaultValue, bool persist = true) return Convert.ToBoolean(GetValue(key, defaultValue, persist)); } - public T GetValueEnum(string key, T defaultValue) + public T GetValueEnum(string key, T defaultValue, bool persist = true) { - return (T)Enum.Parse(typeof(T), GetValue(key, defaultValue), true); + return (T)Enum.Parse(typeof(T), GetValue(key, defaultValue), persist); } public string GetValue(string key, object defaultValue, bool persist = true) @@ -210,7 +223,9 @@ public string GetValue(string key, object defaultValue, bool persist = true) var valueHolder = parentContainer.Descendants(key).ToList(); if (valueHolder.Count() == 1) + { return valueHolder.First().Value.Trim(); + } //Save the value if (persist) diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 3fc54f350..ce3252221 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -6,6 +6,7 @@ using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Update; namespace NzbDrone.Core.Configuration diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index a3cbef057..10a1843a5 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Update; namespace NzbDrone.Core.Configuration { @@ -23,7 +24,6 @@ public interface IConfigService Int32 BlacklistRetryInterval { get; set; } Int32 BlacklistRetryLimit { get; set; } - //Media Management Boolean AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; } String RecycleBin { get; set; } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 06a54557a..c1e0810b2 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -693,10 +693,13 @@ + + + diff --git a/src/NzbDrone.Core/Security.cs b/src/NzbDrone.Core/Security.cs index abc950809..840466e98 100644 --- a/src/NzbDrone.Core/Security.cs +++ b/src/NzbDrone.Core/Security.cs @@ -1,4 +1,5 @@ -using System.Security.Cryptography; +using System.IO; +using System.Security.Cryptography; using System.Text; namespace NzbDrone.Core @@ -7,17 +8,28 @@ public static class Security { public static string SHA256Hash(this string input) { - var stringBuilder = new StringBuilder(); - using (var hash = SHA256Managed.Create()) { var enc = Encoding.UTF8; - var result = hash.ComputeHash(enc.GetBytes(input)); + return GetHash(hash.ComputeHash(enc.GetBytes(input))); + } + } - foreach (var b in result) - { - stringBuilder.Append(b.ToString("x2")); - } + public static string SHA256Hash(this Stream input) + { + using (var hash = SHA256Managed.Create()) + { + return GetHash(hash.ComputeHash(input)); + } + } + + private static string GetHash(byte[] bytes) + { + var stringBuilder = new StringBuilder(); + + foreach (var b in bytes) + { + stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString(); diff --git a/src/NzbDrone.Core/Update/InstallUpdateService.cs b/src/NzbDrone.Core/Update/InstallUpdateService.cs index 01203d007..404ac8f12 100644 --- a/src/NzbDrone.Core/Update/InstallUpdateService.cs +++ b/src/NzbDrone.Core/Update/InstallUpdateService.cs @@ -6,6 +6,7 @@ using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Common.Processes; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Instrumentation.Extensions; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Update.Commands; @@ -27,18 +28,31 @@ public class InstallUpdateService : IInstallUpdates, IExecute GetOtherNzbDroneProcessIds() { var currentId = _processProvider.GetCurrentProcess().Id; - var otherProcesses = _nzbDroneProcessProvider.FindNzbDroneProcesses() - .Select(c => c.Id) - .Except(new[] {currentId}) - .ToList(); + var otherProcesses = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME) + .Union(_processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME)) + .Select(c => c.Id) + .Except(new[] {currentId}) + .ToList(); if (otherProcesses.Any()) { diff --git a/src/NzbDrone.Mono/NzbDrone.Mono.csproj b/src/NzbDrone.Mono/NzbDrone.Mono.csproj index e342f9a16..91d0efeb3 100644 --- a/src/NzbDrone.Mono/NzbDrone.Mono.csproj +++ b/src/NzbDrone.Mono/NzbDrone.Mono.csproj @@ -70,7 +70,6 @@ - diff --git a/src/NzbDrone.Mono/NzbDroneProcessProvider.cs b/src/NzbDrone.Mono/NzbDroneProcessProvider.cs deleted file mode 100644 index 1804c077d..000000000 --- a/src/NzbDrone.Mono/NzbDroneProcessProvider.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using NLog; -using NzbDrone.Common.Model; -using NzbDrone.Common.Processes; - -namespace NzbDrone.Mono -{ - public class NzbDroneProcessProvider : INzbDroneProcessProvider - { - private readonly IProcessProvider _processProvider; - private readonly Logger _logger; - - public NzbDroneProcessProvider(IProcessProvider processProvider, Logger logger) - { - _processProvider = processProvider; - _logger = logger; - } - - public List FindNzbDroneProcesses() - { - var monoProcesses = _processProvider.FindProcessByName("mono"); - - return monoProcesses.Where(c => - { - try - { - var processArgs = _processProvider.StartAndCapture("ps", String.Format("-p {0} -o args=", c.Id)); - - return processArgs.Standard.Any(p => p.Contains(ProcessProvider.NZB_DRONE_PROCESS_NAME + ".exe") || - p.Contains(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME + ".exe")); - } - catch (InvalidOperationException ex) - { - _logger.WarnException("Error getting process arguments", ex); - return false; - } - - }).ToList(); - } - } -} diff --git a/src/NzbDrone.Test.Common/LoggingTest.cs b/src/NzbDrone.Test.Common/LoggingTest.cs index f7ad739fb..e706d3d04 100644 --- a/src/NzbDrone.Test.Common/LoggingTest.cs +++ b/src/NzbDrone.Test.Common/LoggingTest.cs @@ -21,7 +21,7 @@ protected static void InitLogging() LogManager.Configuration = new LoggingConfiguration(); var consoleTarget = new ConsoleTarget { Layout = "${level}: ${message} ${exception}" }; LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget); - LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget)); + LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget)); RegisterExceptionVerification(); } diff --git a/src/NzbDrone.Test.Dummy/DummyApp.cs b/src/NzbDrone.Test.Dummy/DummyApp.cs index 87b04f712..5176dab6f 100644 --- a/src/NzbDrone.Test.Dummy/DummyApp.cs +++ b/src/NzbDrone.Test.Dummy/DummyApp.cs @@ -9,7 +9,9 @@ public class DummyApp static void Main(string[] args) { - Console.WriteLine("Dummy process. ID:{0} Path:{1}", Process.GetCurrentProcess().Id, Process.GetCurrentProcess().MainModule.FileName); + var process = Process.GetCurrentProcess(); + + Console.WriteLine("Dummy process. ID:{0} Name:{1} Path:{2}", process.Id, process.ProcessName, process.MainModule.FileName); Console.ReadLine(); } } diff --git a/src/NzbDrone.Update/NzbDrone.Update.csproj b/src/NzbDrone.Update/NzbDrone.Update.csproj index 0e85877ba..399a39203 100644 --- a/src/NzbDrone.Update/NzbDrone.Update.csproj +++ b/src/NzbDrone.Update/NzbDrone.Update.csproj @@ -51,6 +51,7 @@ Properties\SharedAssemblyInfo.cs + diff --git a/src/NzbDrone.Update/UpdateApp.cs b/src/NzbDrone.Update/UpdateApp.cs index 35d7febca..46de9307e 100644 --- a/src/NzbDrone.Update/UpdateApp.cs +++ b/src/NzbDrone.Update/UpdateApp.cs @@ -1,6 +1,8 @@ using System; using System.IO; +using System.Linq; using NLog; +using NzbDrone.Common; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation; @@ -50,24 +52,60 @@ public static void Main(string[] args) public void Start(string[] args) { - var processId = ParseProcessId(args); + var startupContext = ParseArgs(args); + string targetFolder; - var exeFileInfo = new FileInfo(_processProvider.GetProcessById(processId).StartPath); - var targetFolder = exeFileInfo.Directory.FullName; + if (startupContext.ExecutingApplication.IsNullOrWhiteSpace()) + { + var exeFileInfo = new FileInfo(_processProvider.GetProcessById(startupContext.ProcessId).StartPath); + targetFolder = exeFileInfo.Directory.FullName; + } + else + { + var exeFileInfo = new FileInfo(startupContext.ExecutingApplication); + targetFolder = exeFileInfo.Directory.FullName; + } + logger.Info("Starting update process. Target Path:{0}", targetFolder); _installUpdateService.Start(targetFolder); } - private int ParseProcessId(string[] args) + private UpdateStartupContext ParseArgs(string[] args) { - int id; - if (args == null || !Int32.TryParse(args[0], out id) || id <= 0) + if (args == null || !args.Any()) { - throw new ArgumentOutOfRangeException("args", "Invalid process ID"); + throw new ArgumentOutOfRangeException("args", "args must be specified"); } - logger.Debug("NzbDrone processId:{0}", id); + var startupContext = new UpdateStartupContext + { + ProcessId = ParseProcessId(args[0]) + }; + + if (args.Count() == 1) + { + return startupContext; + } + + if (args.Count() >= 3) + { + startupContext.UpdateLocation = args[1]; + startupContext.ExecutingApplication = args[2]; + } + + return startupContext; + } + + private int ParseProcessId(string arg) + { + int id; + if (!Int32.TryParse(arg, out id) || id <= 0) + { + throw new ArgumentOutOfRangeException("arg", "Invalid process ID"); + } + + logger.Debug("NzbDrone process ID: {0}", id); return id; } } diff --git a/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs b/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs index ec9a80a96..aeed37c45 100644 --- a/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs +++ b/src/NzbDrone.Update/UpdateEngine/DetectApplicationType.cs @@ -1,4 +1,5 @@ using NzbDrone.Common; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Processes; namespace NzbDrone.Update.UpdateEngine @@ -21,6 +22,12 @@ public DetectApplicationType(IServiceProvider serviceProvider, IProcessProvider public AppType GetAppType() { + if (OsInfo.IsMono) + { + //Tehcnically its the console, but its been renamed for mono (Linux/OS X) + return AppType.Normal; + } + if (_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME) && _serviceProvider.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME)) { diff --git a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs index f1b731e34..e70027a3a 100644 --- a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs +++ b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs @@ -82,7 +82,6 @@ public void Start(string installationFolder) _backupAndRestore.Restore(installationFolder); _logger.FatalException("Failed to copy upgrade package to target folder.", e); } - } finally { diff --git a/src/NzbDrone.Update/UpdateEngine/TerminateNzbDrone.cs b/src/NzbDrone.Update/UpdateEngine/TerminateNzbDrone.cs index 329c9555e..4c8934f03 100644 --- a/src/NzbDrone.Update/UpdateEngine/TerminateNzbDrone.cs +++ b/src/NzbDrone.Update/UpdateEngine/TerminateNzbDrone.cs @@ -1,6 +1,7 @@ using System; using NLog; using NzbDrone.Common; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Processes; using IServiceProvider = NzbDrone.Common.IServiceProvider; @@ -26,6 +27,15 @@ public TerminateNzbDrone(IServiceProvider serviceProvider, IProcessProvider proc public void Terminate() { + if (OsInfo.IsMono) + { + _logger.Info("Stopping all instances"); + _processProvider.KillAll(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME); + _processProvider.KillAll(ProcessProvider.NZB_DRONE_PROCESS_NAME); + + return; + } + _logger.Info("Stopping all running services"); if (_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME) @@ -35,7 +45,6 @@ public void Terminate() { _logger.Info("NzbDrone Service is installed and running"); _serviceProvider.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME); - } catch (Exception e) { diff --git a/src/NzbDrone.Update/UpdateStartupContext.cs b/src/NzbDrone.Update/UpdateStartupContext.cs new file mode 100644 index 000000000..51b6bf103 --- /dev/null +++ b/src/NzbDrone.Update/UpdateStartupContext.cs @@ -0,0 +1,11 @@ +using System; + +namespace NzbDrone.Update +{ + public class UpdateStartupContext + { + public Int32 ProcessId { get; set; } + public String ExecutingApplication { get; set; } + public String UpdateLocation { get; set; } + } +} diff --git a/src/NzbDrone.Windows/NzbDrone.Windows.csproj b/src/NzbDrone.Windows/NzbDrone.Windows.csproj index 77e47f03c..607f09a4e 100644 --- a/src/NzbDrone.Windows/NzbDrone.Windows.csproj +++ b/src/NzbDrone.Windows/NzbDrone.Windows.csproj @@ -63,7 +63,6 @@ - diff --git a/src/NzbDrone.Windows/NzbDroneProcessProvider.cs b/src/NzbDrone.Windows/NzbDroneProcessProvider.cs deleted file mode 100644 index 1e18b6c50..000000000 --- a/src/NzbDrone.Windows/NzbDroneProcessProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Common.Model; -using NzbDrone.Common.Processes; - -namespace NzbDrone.Windows -{ - public class NzbDroneProcessProvider : INzbDroneProcessProvider - { - private readonly IProcessProvider _processProvider; - - public NzbDroneProcessProvider(IProcessProvider processProvider) - { - _processProvider = processProvider; - } - - public List FindNzbDroneProcesses() - { - var consoleProcesses = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME); - var winformProcesses = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME); - - return consoleProcesses.Concat(winformProcesses).ToList(); - } - } -} diff --git a/src/UI/Settings/General/GeneralView.js b/src/UI/Settings/General/GeneralView.js index 2e63d2de5..b28ed659c 100644 --- a/src/UI/Settings/General/GeneralView.js +++ b/src/UI/Settings/General/GeneralView.js @@ -12,19 +12,22 @@ define( template: 'Settings/General/GeneralViewTemplate', events: { - 'change .x-auth' : '_setAuthOptionsVisibility', - 'change .x-ssl' : '_setSslOptionsVisibility', - 'click .x-reset-api-key' : '_resetApiKey' + 'change .x-auth' : '_setAuthOptionsVisibility', + 'change .x-ssl' : '_setSslOptionsVisibility', + 'click .x-reset-api-key' : '_resetApiKey', + 'change .x-update-mechanism' : '_setScriptGroupVisibility' }, ui: { - authToggle : '.x-auth', - authOptions : '.x-auth-options', - sslToggle : '.x-ssl', - sslOptions : '.x-ssl-options', - resetApiKey : '.x-reset-api-key', - copyApiKey : '.x-copy-api-key', - apiKeyInput : '.x-api-key' + authToggle : '.x-auth', + authOptions : '.x-auth-options', + sslToggle : '.x-ssl', + sslOptions : '.x-ssl-options', + resetApiKey : '.x-reset-api-key', + copyApiKey : '.x-copy-api-key', + apiKeyInput : '.x-api-key', + updateMechanism : '.x-update-mechanism', + scriptGroup : '.x-script-group' }, initialize: function () { @@ -40,6 +43,10 @@ define( this.ui.sslOptions.hide(); } + if (!this._showScriptGroup()) { + this.ui.scriptGroup.hide(); + } + CommandController.bindToCommand({ element: this.ui.resetApiKey, command: { @@ -79,7 +86,7 @@ define( }, _resetApiKey: function () { - if (window.confirm("Reset API Key?")) { + if (window.confirm('Reset API Key?')) { CommandController.Execute('resetApiKey', { name : 'resetApiKey' }); @@ -90,6 +97,21 @@ define( if (options.command.get('name') === 'resetapikey') { this.model.fetch(); } + }, + + _setScriptGroupVisibility: function () { + + if (this._showScriptGroup()) { + this.ui.scriptGroup.slideDown(); + } + + else { + this.ui.scriptGroup.slideUp(); + } + }, + + _showScriptGroup: function () { + return this.ui.updateMechanism.val() === 'script'; } }); diff --git a/src/UI/Settings/General/GeneralViewTemplate.html b/src/UI/Settings/General/GeneralViewTemplate.html index f0968e721..cfbca24bd 100644 --- a/src/UI/Settings/General/GeneralViewTemplate.html +++ b/src/UI/Settings/General/GeneralViewTemplate.html @@ -102,7 +102,7 @@
-
+
@@ -174,9 +174,8 @@
- {{#if_windows}}
- Development + Updating
@@ -186,28 +185,56 @@
- - - + {{#if_mono}} +
Please see: the wiki for more information
- - - +
+ - - - - +
+
+
+
- - - - - - +
+ + +
+ +
+ +
+ +
+
+ +
+ + +
+ +
+ +
+ +
+
+ {{/if_mono}} - {{/if_windows}}
diff --git a/src/UI/System/Update/UpdateItemViewTemplate.html b/src/UI/System/Update/UpdateItemViewTemplate.html index c8bcc3238..95b56de51 100644 --- a/src/UI/System/Update/UpdateItemViewTemplate.html +++ b/src/UI/System/Update/UpdateItemViewTemplate.html @@ -5,17 +5,9 @@ - {{ShortDate releaseDate}} {{#if installed}}{{/if}} - {{#if_windows}} - {{#if isUpgrade}} - Install - {{/if}} - {{else}} - {{#if isUpgrade}} - - Install - - {{/if}} - {{/if_windows}} + {{#if isUpgrade}} + Install + {{/if}}