diff --git a/src/chocolatey.tests/infrastructure.app/services/AutomaticUninstallerServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/AutomaticUninstallerServiceSpecs.cs index 5706edd806..b30e6baa6a 100644 --- a/src/chocolatey.tests/infrastructure.app/services/AutomaticUninstallerServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/AutomaticUninstallerServiceSpecs.cs @@ -64,6 +64,7 @@ public override void Context() service.WaitForCleanup = false; config.Features.AutoUninstaller = true; config.PromptForConfirmation = false; + config.PackageNames = "regular"; package.Setup(p => p.Id).Returns("regular"); package.Setup(p => p.Version).Returns(new SemanticVersion("1.2.0")); packageResult = new PackageResult(package.Object, "c:\\packages\\thispackage"); @@ -471,7 +472,7 @@ public void should_call_command_executor() Times.Once); } } - + public class when_uninstall_string_is_split_by_quotes : AutomaticUninstallerServiceSpecsBase { private readonly string uninstallStringWithQuoteSeparation = @"""C:\Program Files (x86)\WinDirStat\Uninstall.exe"" ""WinDir Stat"""; @@ -612,6 +613,111 @@ public void should_not_call_command_executor() } } + public class when_AutomaticUninstallerService_is_passed_uninstall_arguments_from_command_line : AutomaticUninstallerServiceSpecsBase + { + IInstaller _installerType = new InnoSetupInstaller(); + + public override void Context() + { + base.Context(); + registryKeys.Clear(); + registryKeys.Add( + new RegistryApplicationKey + { + DisplayName = expectedDisplayName, + InstallLocation = @"C:\Program Files (x86)\WinDirStat", + UninstallString = originalUninstallString, + HasQuietUninstall = false, + KeyPath = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\WinDirStat", + InstallerType = _installerType.InstallerType, + }); + packageInformation.RegistrySnapshot = new Registry("123", registryKeys); + + config.InstallArguments = "/bob /nope"; + } + + public override void Because() + { + service.run(packageResult, config); + } + + [Fact] + public void should_call_get_package_information() + { + packageInfoService.Verify(s => s.get_package_information(It.IsAny()), Times.Once); + } + + [Fact] + public void should_call_command_executor_appending_passed_arguments() + { + var uninstallArgs = _installerType.build_uninstall_command_arguments().trim_safe(); + + uninstallArgs += " {0}".format_with(config.InstallArguments); + + commandExecutor.Verify( + c => + c.execute( + expectedUninstallString, + uninstallArgs, + It.IsAny(), + It.IsAny>(), + It.IsAny>(), + It.IsAny()), + Times.Once); + } + } + + public class when_AutomaticUninstallerService_is_passed_overriding_uninstall_arguments_from_command_line : AutomaticUninstallerServiceSpecsBase + { + IInstaller _installerType = new InnoSetupInstaller(); + + public override void Context() + { + base.Context(); + registryKeys.Clear(); + registryKeys.Add( + new RegistryApplicationKey + { + DisplayName = expectedDisplayName, + InstallLocation = @"C:\Program Files (x86)\WinDirStat", + UninstallString = originalUninstallString, + HasQuietUninstall = false, + KeyPath = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\WinDirStat", + InstallerType = _installerType.InstallerType, + }); + packageInformation.RegistrySnapshot = new Registry("123", registryKeys); + + config.InstallArguments = "/bob /nope"; + config.OverrideArguments = true; + } + + public override void Because() + { + service.run(packageResult, config); + } + + [Fact] + public void should_call_get_package_information() + { + packageInfoService.Verify(s => s.get_package_information(It.IsAny()), Times.Once); + } + + [Fact] + public void should_call_command_executor_with_only_passed_arguments() + { + commandExecutor.Verify( + c => + c.execute( + expectedUninstallString, + config.InstallArguments, + It.IsAny(), + It.IsAny>(), + It.IsAny>(), + It.IsAny()), + Times.Once); + } + } + public class when_AutomaticUninstallerService_defines_uninstall_switches : AutomaticUninstallerServiceSpecsBase { private Action because; diff --git a/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs b/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs index a749186a6e..5bf0d2be41 100644 --- a/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs +++ b/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs @@ -30,6 +30,7 @@ namespace chocolatey.infrastructure.app.services using infrastructure.commands; using logging; using results; + using utility; public class AutomaticUninstallerService : IAutomaticUninstallerService { @@ -97,16 +98,30 @@ public void run(PackageResult packageResult, ChocolateyConfiguration config) this.Log().Debug(" Sleeping for {0} seconds to allow Windows to finish cleaning up.".format_with(SLEEP_TIME)); Thread.Sleep((int)TimeSpan.FromSeconds(SLEEP_TIME).TotalMilliseconds); } - + foreach (var key in registryKeys.or_empty_list_if_null()) { - var packageCacheLocation = _fileSystem.combine_paths(_fileSystem.get_full_path(config.CacheLocation), pkgInfo.Package.Id, pkgInfo.Package.Version.to_string()); + var packageCacheLocation = _fileSystem.combine_paths(_fileSystem.get_full_path(config.CacheLocation), package.Id, package.Version.to_string()); remove(key, config, packageResult, packageCacheLocation); } } public void remove(RegistryApplicationKey key, ChocolateyConfiguration config, PackageResult packageResult, string packageCacheLocation) { + var userProvidedUninstallArguments = string.Empty; + var userOverrideUninstallArguments = false; + var package = packageResult.Package; + if (package != null) + { + if (!PackageUtility.package_is_a_dependency(config, package.Id) || config.ApplyInstallArgumentsToDependencies) + { + userProvidedUninstallArguments = config.InstallArguments; + userOverrideUninstallArguments = config.OverrideArguments; + + if (!string.IsNullOrWhiteSpace(userProvidedUninstallArguments)) this.Log().Debug(ChocolateyLoggers.Verbose, " Using user passed {2}uninstaller args for {0}:'{1}'".format_with(package.Id, userProvidedUninstallArguments.escape_curly_braces(), userOverrideUninstallArguments ? "overriding " : string.Empty)); + } + } + //todo: if there is a local package, look to use it in the future if (string.IsNullOrWhiteSpace(key.UninstallString)) { @@ -145,6 +160,7 @@ public void remove(RegistryApplicationKey key, ChocolateyConfiguration config, P } } var uninstallArgs = key.UninstallString.to_string().Replace(uninstallExe.to_string(), string.Empty).trim_safe(); + uninstallExe = uninstallExe.remove_surrounding_quotes(); this.Log().Debug(() => " Uninstaller path is '{0}'".format_with(uninstallExe)); @@ -175,6 +191,20 @@ public void remove(RegistryApplicationKey key, ChocolateyConfiguration config, P uninstallArgs += " " + installer.build_uninstall_command_arguments(); } + if (!string.IsNullOrWhiteSpace(userProvidedUninstallArguments)) + { + if (userOverrideUninstallArguments) + { + this.Log().Debug(() => " Replacing original uninstall arguments of '{0}' with '{1}'".format_with(uninstallArgs.escape_curly_braces(),userProvidedUninstallArguments.escape_curly_braces())); + uninstallArgs = userProvidedUninstallArguments; + } + else + { + this.Log().Debug(() => " Appending original uninstall arguments with '{0}'".format_with(userProvidedUninstallArguments.escape_curly_braces())); + uninstallArgs += " " + userProvidedUninstallArguments; + } + } + this.Log().Debug(() => " Setting up uninstall logging directory at {0}".format_with(packageCacheLocation.escape_curly_braces())); _fileSystem.create_directory_if_not_exists(_fileSystem.get_directory_name(packageCacheLocation)); uninstallArgs = uninstallArgs.Replace(InstallTokens.PACKAGE_LOCATION, packageCacheLocation);