diff --git a/NzbDrone.App.Test/RouterTest.cs b/NzbDrone.App.Test/RouterTest.cs index e9bf8c2a8..6235192c3 100644 --- a/NzbDrone.App.Test/RouterTest.cs +++ b/NzbDrone.App.Test/RouterTest.cs @@ -1,4 +1,5 @@ -using System.ServiceProcess; +using System.IO; +using System.ServiceProcess; using FluentAssertions; using Moq; using NUnit.Framework; @@ -46,10 +47,10 @@ namespace NzbDrone.App.Test [Test] public void Route_should_call_install_service_when_application_mode_is_install() { - WithStrictMocker(); - var serviceProviderMock = Mocker.GetMock(); + var serviceProviderMock = Mocker.GetMock(MockBehavior.Strict); serviceProviderMock.Setup(c => c.Install(ServiceProvider.NZBDRONE_SERVICE_NAME)); serviceProviderMock.Setup(c => c.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)).Returns(false); + serviceProviderMock.Setup(c => c.Start(ServiceProvider.NZBDRONE_SERVICE_NAME)); Mocker.GetMock().SetupGet(c => c.IsUserInteractive).Returns(true); Mocker.Resolve().Route(ApplicationMode.InstallService); @@ -61,7 +62,6 @@ namespace NzbDrone.App.Test [Test] public void Route_should_call_uninstall_service_when_application_mode_is_uninstall() { - WithStrictMocker(); var serviceProviderMock = Mocker.GetMock(); serviceProviderMock.Setup(c => c.UnInstall(ServiceProvider.NZBDRONE_SERVICE_NAME)); Mocker.GetMock().SetupGet(c => c.IsUserInteractive).Returns(true); @@ -75,7 +75,6 @@ namespace NzbDrone.App.Test [Test] public void Route_should_call_console_service_when_application_mode_is_console() { - WithStrictMocker(); var consoleProvider = Mocker.GetMock(); var appServerProvider = Mocker.GetMock(); consoleProvider.Setup(c => c.WaitForClose()); @@ -94,7 +93,6 @@ namespace NzbDrone.App.Test [TestCase(ApplicationMode.Help)] public void Route_should_call_service_start_when_run_in_service_more(ApplicationMode applicationMode) { - WithStrictMocker(); var envMock = Mocker.GetMock(); var serviceProvider = Mocker.GetMock(); @@ -111,7 +109,6 @@ namespace NzbDrone.App.Test [Test] public void show_error_on_install_if_service_already_exist() { - WithStrictMocker(); var consoleMock = Mocker.GetMock(); var serviceMock = Mocker.GetMock(); Mocker.GetMock().SetupGet(c => c.IsUserInteractive).Returns(true); @@ -127,7 +124,6 @@ namespace NzbDrone.App.Test [Test] public void show_error_on_uninstall_if_service_doesnt_exist() { - WithStrictMocker(); var consoleMock = Mocker.GetMock(); var serviceMock = Mocker.GetMock(); Mocker.GetMock().SetupGet(c => c.IsUserInteractive).Returns(true); @@ -139,5 +135,30 @@ namespace NzbDrone.App.Test Mocker.VerifyAllMocks(); } + + [Test] + public void should_delete_service_bat_files_if_they_exist() + { + WithTempAsAppPath(); + + var bat1 = @"c:\nzbdrone\ServiceInstall.bat"; + var bat2 = @"c:\nzbdrone\ServiceUninstall.bat"; + var bat3 = @"c:\nzbdrone\Someother.bat"; + var file1 = @"c:\nzbdrone\ServiceInstall.exe"; + var file2 = @"c:\nzbdrone\ServiceInstall.dat"; + + var files = new string[] {bat1, bat2, bat3, file1, file2}; + + Mocker.GetMock() + .Setup(c => c.GetFiles(VirtualPath, SearchOption.TopDirectoryOnly)).Returns(files); + + Mocker.Resolve().Route(ApplicationMode.Console); + + Mocker.GetMock().Verify(c=>c.DeleteFile(bat1)); + Mocker.GetMock().Verify(c=>c.DeleteFile(bat2)); + Mocker.GetMock().Verify(c=>c.DeleteFile(bat3),Times.Never()); + Mocker.GetMock().Verify(c=>c.DeleteFile(file1),Times.Never()); + Mocker.GetMock().Verify(c=>c.DeleteFile(file2),Times.Never()); + } } } diff --git a/NzbDrone.Common.Test/ServiceProviderTests.cs b/NzbDrone.Common.Test/ServiceProviderTests.cs index 99488c7eb..c835816a3 100644 --- a/NzbDrone.Common.Test/ServiceProviderTests.cs +++ b/NzbDrone.Common.Test/ServiceProviderTests.cs @@ -63,6 +63,8 @@ namespace NzbDrone.Common.Test serviceProvider.ServiceExist(TEMP_SERVICE_NAME).Should().BeTrue(); serviceProvider.UnInstall(TEMP_SERVICE_NAME); serviceProvider.ServiceExist(TEMP_SERVICE_NAME).Should().BeFalse(); + + ExceptionVerification.ExpectedWarns(1); } [Test] diff --git a/NzbDrone.Common/ServiceProvider.cs b/NzbDrone.Common/ServiceProvider.cs index 788a52a1f..46c967dcc 100644 --- a/NzbDrone.Common/ServiceProvider.cs +++ b/NzbDrone.Common/ServiceProvider.cs @@ -65,6 +65,9 @@ namespace NzbDrone.Common public virtual void UnInstall(string serviceName) { Logger.Info("Uninstalling {0} service", serviceName); + + Stop(serviceName); + var serviceInstaller = new ServiceInstaller(); var context = new InstallContext("service_uninstall.log", null); diff --git a/NzbDrone.Web/Models/SystemSettingsModel.cs b/NzbDrone.Web/Models/SystemSettingsModel.cs index c1ebfb5ee..c13e25538 100644 --- a/NzbDrone.Web/Models/SystemSettingsModel.cs +++ b/NzbDrone.Web/Models/SystemSettingsModel.cs @@ -14,11 +14,11 @@ namespace NzbDrone.Web.Models public int Port { get; set; } [DisplayName("Launch Browser")] - [Description("Start default webrowser when NzbDrone starts?")] + [Description("Start web browser when NzbDrone starts?")] public bool LaunchBrowser { get; set; } [DisplayName("Authentication")] - [Description("Secure the webserver with Authentication?")] + [Description("Secure the server with authentication?")] public AuthenticationType AuthenticationType { get; set; } public SelectList AuthTypeSelectList { get; set; } diff --git a/NzbDrone.sln b/NzbDrone.sln index 0610c4420..54c99362c 100644 --- a/NzbDrone.sln +++ b/NzbDrone.sln @@ -29,6 +29,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test.Common", "Test.Common" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Web.UI.Automation", "NzbDrone.Web.UI.Test\NzbDrone.Web.UI.Automation.csproj", "{3CCD64E1-84DA-4853-B7EF-98B02FD4E39E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServiceHelpers", "ServiceHelpers", "{F9E67978-5CD6-4A5F-827B-4249711C0B02}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceInstall", "ServiceHelpers\ServiceInstall\ServiceInstall.csproj", "{6BCE712F-846D-4846-9D1B-A66B858DA755}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUninstall", "ServiceHelpers\ServiceUninstall\ServiceUninstall.csproj", "{700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -191,6 +197,30 @@ Global {3CCD64E1-84DA-4853-B7EF-98B02FD4E39E}.Release|Mixed Platforms.Build.0 = Release|Any CPU {3CCD64E1-84DA-4853-B7EF-98B02FD4E39E}.Release|x64.ActiveCfg = Release|Any CPU {3CCD64E1-84DA-4853-B7EF-98B02FD4E39E}.Release|x86.ActiveCfg = Release|Any CPU + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x64.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x86.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x86.Build.0 = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|Any CPU.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|Mixed Platforms.Build.0 = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x64.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x86.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x86.Build.0 = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|Any CPU.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x64.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x86.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x86.Build.0 = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|Any CPU.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|Mixed Platforms.Build.0 = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x64.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x86.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -204,6 +234,8 @@ Global {3CCD64E1-84DA-4853-B7EF-98B02FD4E39E} = {57A04B72-8088-4F75-A582-1158CF8291F7} {CADDFCE0-7509-4430-8364-2074E1EEFCA2} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} {FAFB5948-A222-4CF6-AD14-026BE7564802} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} + {6BCE712F-846D-4846-9D1B-A66B858DA755} = {F9E67978-5CD6-4A5F-827B-4249711C0B02} + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4} = {F9E67978-5CD6-4A5F-827B-4249711C0B02} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35 diff --git a/NzbDrone/NzbDrone.csproj b/NzbDrone/NzbDrone.csproj index 238926a52..edd2e841c 100644 --- a/NzbDrone/NzbDrone.csproj +++ b/NzbDrone/NzbDrone.csproj @@ -56,6 +56,9 @@ NzbDrone.AppMain + + OnOutputUpdated + True @@ -94,13 +97,7 @@ - - PreserveNewest - - - PreserveNewest - @@ -138,6 +135,10 @@ + + + + + \ No newline at end of file diff --git a/ServiceHelpers/ServiceInstall/app.manifest b/ServiceHelpers/ServiceInstall/app.manifest new file mode 100644 index 000000000..55b56fb24 --- /dev/null +++ b/ServiceHelpers/ServiceInstall/app.manifest @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ServiceHelpers/ServiceInstall/green_puzzle.ico b/ServiceHelpers/ServiceInstall/green_puzzle.ico new file mode 100644 index 000000000..1ed3f4b9f Binary files /dev/null and b/ServiceHelpers/ServiceInstall/green_puzzle.ico differ diff --git a/ServiceHelpers/ServiceUninstall/Program.cs b/ServiceHelpers/ServiceUninstall/Program.cs new file mode 100644 index 000000000..5d6cb9a80 --- /dev/null +++ b/ServiceHelpers/ServiceUninstall/Program.cs @@ -0,0 +1,16 @@ +using System.Linq; +using System; +using UninstallService; + +namespace ServiceUninstall +{ + public static class Program + { + static void Main() + { + ServiceHelper.Run(@"/u"); + Console.WriteLine("Press any key to continue"); + Console.ReadLine(); + } + } +} diff --git a/ServiceHelpers/ServiceUninstall/Properties/AssemblyInfo.cs b/ServiceHelpers/ServiceUninstall/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..b0d13d043 --- /dev/null +++ b/ServiceHelpers/ServiceUninstall/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("UninstallService")] +[assembly: Guid("0a964b21-9de9-40b3-9378-0474fd5f21a8")] + +[assembly: AssemblyVersion("0.0.0.*")] +[assembly: AssemblyFileVersion("0.0.0.*")] \ No newline at end of file diff --git a/ServiceHelpers/ServiceUninstall/ServiceHelper.cs b/ServiceHelpers/ServiceUninstall/ServiceHelper.cs new file mode 100644 index 000000000..bdc0c5b18 --- /dev/null +++ b/ServiceHelpers/ServiceUninstall/ServiceHelper.cs @@ -0,0 +1,69 @@ +using System.Linq; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Security.Principal; + +namespace UninstallService +{ + internal static class ServiceHelper + { + private static string NzbDroneExe + { + get + { + return Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName, "nzbdrone.exe"); + } + } + + private static bool IsAnAdministrator() + { + WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + + internal static void Run(string arg) + { + if (!File.Exists(NzbDroneExe)) + { + Console.WriteLine("Unable to find NzbDrone.exe in the current directory."); + return; + } + + if (!IsAnAdministrator()) + { + Console.WriteLine("Access denied. Please run as administrator."); + return; + } + + var startInfo = new ProcessStartInfo + { + FileName = NzbDroneExe, + Arguments = arg, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + var process = new Process { StartInfo = startInfo }; + process.OutputDataReceived += (OnDataReceived); + process.ErrorDataReceived += (OnDataReceived); + + process.Start(); + + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + + process.WaitForExit(); + + } + + private static void OnDataReceived(object sender, DataReceivedEventArgs e) + { + Console.WriteLine(e.Data); + } + + } +} \ No newline at end of file diff --git a/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj b/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj new file mode 100644 index 000000000..18331752b --- /dev/null +++ b/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj @@ -0,0 +1,80 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4} + Exe + Properties + ServiceUninstall + ServiceUninstall + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + ServiceUninstall.Program + + + red_puzzle.ico + + + app.manifest + + + + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + Designer + + + + + + + + + + + + "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\mt.exe" -manifest "$(ProjectDir)app.manifest" –outputresource:"$(TargetDir)$(TargetFileName)";#1 + + + \ No newline at end of file diff --git a/ServiceHelpers/ServiceUninstall/app.manifest b/ServiceHelpers/ServiceUninstall/app.manifest new file mode 100644 index 000000000..55b56fb24 --- /dev/null +++ b/ServiceHelpers/ServiceUninstall/app.manifest @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ServiceHelpers/ServiceUninstall/red_puzzle.ico b/ServiceHelpers/ServiceUninstall/red_puzzle.ico new file mode 100644 index 000000000..b7d1bedec Binary files /dev/null and b/ServiceHelpers/ServiceUninstall/red_puzzle.ico differ diff --git a/package.bat b/package.bat index 46d117d61..29747ee67 100644 --- a/package.bat +++ b/package.bat @@ -9,6 +9,9 @@ del nzbdrone*.zip /Q /F xcopy IISExpress %TARGET%\IISExpress /E /V /I /Y +xcopy ServiceHelpers\ServiceInstall\bin\Release\*.exe %TARGET%\ /E /V /I /Y +xcopy ServiceHelpers\ServiceUninstall\bin\Release\*.exe %TARGET%\ /E /V /I /Y + xcopy NzbDrone\bin\Debug\*.* %TARGET%\ /E /V /I /Y xcopy NzbDrone\bin\Release\*.* %TARGET%\ /E /V /I /Y