diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUninstallCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUninstallCommandSpecs.cs index 3442cacdd8..af710ed6b7 100644 --- a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUninstallCommandSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUninstallCommandSpecs.cs @@ -182,6 +182,78 @@ public void Should_add_short_version_of_skip_hooks_to_the_option_set() { _optionSet.Contains("skiphooks").Should().BeTrue(); } + + [Fact] + public void Should_add_short_version_of_userememberedargs_to_the_option_set() + { + _optionSet.Contains("userememberedargs").Should().BeTrue(); + } + + [Fact] + public void Should_add_short_version_of_userememberedarguments_to_the_option_set() + { + _optionSet.Contains("userememberedarguments").Should().BeTrue(); + } + + [Fact] + public void Should_add_short_version_of_userememberedoptions_to_the_option_set() + { + _optionSet.Contains("userememberedoptions").Should().BeTrue(); + } + + [Fact] + public void Should_add_userememberedargs_to_the_option_set() + { + _optionSet.Contains("use-remembered-args").Should().BeTrue(); + } + + [Fact] + public void Should_add_userememberedarguments_to_the_option_set() + { + _optionSet.Contains("use-remembered-arguments").Should().BeTrue(); + } + + [Fact] + public void Should_add_userememberedoptions_to_the_option_set() + { + _optionSet.Contains("use-remembered-options").Should().BeTrue(); + } + + [Fact] + public void Should_add_short_version_of_ignorerememberedargs_to_the_option_set() + { + _optionSet.Contains("ignorerememberedargs").Should().BeTrue(); + } + + [Fact] + public void Should_add_short_version_of_ignorerememberedarguments_to_the_option_set() + { + _optionSet.Contains("ignorerememberedarguments").Should().BeTrue(); + } + + [Fact] + public void Should_add_short_version_of_ignorerememberedoptions_to_the_option_set() + { + _optionSet.Contains("ignorerememberedoptions").Should().BeTrue(); + } + + [Fact] + public void Should_add_ignorerememberedargs_to_the_option_set() + { + _optionSet.Contains("ignore-remembered-args").Should().BeTrue(); + } + + [Fact] + public void Should_add_ignorerememberedarguments_to_the_option_set() + { + _optionSet.Contains("ignore-remembered-arguments").Should().BeTrue(); + } + + [Fact] + public void Should_add_ignorerememberedoptions_to_the_option_set() + { + _optionSet.Contains("ignore-remembered-options").Should().BeTrue(); + } } public class When_handling_additional_argument_parsing : ChocolateyUninstallCommandSpecsBase diff --git a/src/chocolatey/infrastructure.app/ApplicationParameters.cs b/src/chocolatey/infrastructure.app/ApplicationParameters.cs index 3e62b1a0b1..eb38fc9513 100644 --- a/src/chocolatey/infrastructure.app/ApplicationParameters.cs +++ b/src/chocolatey/infrastructure.app/ApplicationParameters.cs @@ -230,6 +230,7 @@ public static class Features public static readonly string ShowDownloadProgress = "showDownloadProgress"; public static readonly string StopOnFirstPackageFailure = "stopOnFirstPackageFailure"; public static readonly string UseRememberedArgumentsForUpgrades = "useRememberedArgumentsForUpgrades"; + public static readonly string UseRememberedArgumentsForUninstalls = "useRememberedArgumentsForUninstalls"; public static readonly string IgnoreUnfoundPackagesOnUpgradeOutdated = "ignoreUnfoundPackagesOnUpgradeOutdated"; public static readonly string SkipPackageUpgradesWhenNotInstalled = "skipPackageUpgradesWhenNotInstalled"; public static readonly string RemovePackageInformationOnUninstall = "removePackageInformationOnUninstall"; diff --git a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs index 8dd3295af0..6eea3d0d84 100644 --- a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs +++ b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs @@ -332,6 +332,7 @@ private static void SetAllFeatureFlags(ChocolateyConfiguration config, ConfigFil config.Features.ShowDownloadProgress = SetFeatureFlag(ApplicationParameters.Features.ShowDownloadProgress, configFileSettings, defaultEnabled: true, description: "Show Download Progress - Show download progress percentages in the CLI."); config.Features.StopOnFirstPackageFailure = SetFeatureFlag(ApplicationParameters.Features.StopOnFirstPackageFailure, configFileSettings, defaultEnabled: false, description: "Stop On First Package Failure - Stop running install, upgrade or uninstall on first package failure instead of continuing with others. As this will affect upgrade all, it is normally recommended to leave this off."); config.Features.UseRememberedArgumentsForUpgrades = SetFeatureFlag(ApplicationParameters.Features.UseRememberedArgumentsForUpgrades, configFileSettings, defaultEnabled: false, description: "Use Remembered Arguments For Upgrades - When running upgrades, use arguments for upgrade that were used for installation ('remembered'). This is helpful when running upgrade for all packages. This is considered in preview and will be flipped to on by default in a future release."); + config.Features.UseRememberedArgumentsForUninstalls = SetFeatureFlag(ApplicationParameters.Features.UseRememberedArgumentsForUninstalls, configFileSettings, defaultEnabled: false, description: "Use Remembered Arguments For Uninstalls - When running uninstalls, use arguments for uninstall that were used for installation or upgrade ('remembered'). Does not include --install-args. Available in 2.4.0+. This is considered in preview and will be flipped to on by default in a future release."); config.Features.IgnoreUnfoundPackagesOnUpgradeOutdated = SetFeatureFlag(ApplicationParameters.Features.IgnoreUnfoundPackagesOnUpgradeOutdated, configFileSettings, defaultEnabled: false, description: "Ignore Unfound Packages On Upgrade Outdated - When checking outdated or upgrades, if a package is not found against sources specified, don't report the package at all."); config.Features.SkipPackageUpgradesWhenNotInstalled = SetFeatureFlag(ApplicationParameters.Features.SkipPackageUpgradesWhenNotInstalled, configFileSettings, defaultEnabled: false, description: "Skip Packages Not Installed During Upgrade - if a package is not installed, do not install it during the upgrade process."); config.Features.RemovePackageInformationOnUninstall = SetFeatureFlag(ApplicationParameters.Features.RemovePackageInformationOnUninstall, configFileSettings, defaultEnabled: false, description: "Remove Stored Package Information On Uninstall - When a package is uninstalled, should the stored package information also be removed? "); @@ -419,11 +420,16 @@ private static void SetGlobalOptions(IList args, ChocolateyConfiguration if (timeout > 0 || timeoutString.IsEqualTo("0")) { config.CommandExecutionTimeoutSeconds = timeout; + config.CommandExecutionTimeoutSecondsArgumentWasPassed = true; } }) .Add("c=|cache=|cachelocation=|cache-location=", "CacheLocation - Location for download cache, defaults to %TEMP% or value in chocolatey.config file.", - option => config.CacheLocation = option.UnquoteSafe()) + option => + { + config.CacheLocation = option.UnquoteSafe(); + config.CacheLocationArgumentWasPassed = true; + }) .Add("allowunofficial|allow-unofficial|allowunofficialbuild|allow-unofficial-build", "AllowUnofficialBuild - When not using the official build you must set this flag for choco to continue.", option => config.AllowUnofficialBuild = option != null) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyUninstallCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyUninstallCommand.cs index 8abb40f6f4..1b6abee572 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyUninstallCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyUninstallCommand.cs @@ -146,6 +146,18 @@ public virtual void ConfigureArgumentParser(OptionSet optionSet, ChocolateyConfi "Skip hooks - Do not run hook scripts. Available in 1.2.0+", option => configuration.SkipHookScripts = option != null ) + .Add("userememberedargs|userememberedarguments|userememberedoptions|use-remembered-args|use-remembered-arguments|use-remembered-options", + "Use Remembered Options for Uninstall - use the arguments and options used during install/upgrade for uninstall. Does not override arguments being passed at runtime. Overrides the default feature '{0}' set to '{1}'. Available in 2.4.0+.".FormatWith(ApplicationParameters.Features.UseRememberedArgumentsForUninstalls, configuration.Features.UseRememberedArgumentsForUninstalls.ToString()), + option => + { + if (option != null) configuration.Features.UseRememberedArgumentsForUninstalls = true; + }) + .Add("ignorerememberedargs|ignorerememberedarguments|ignorerememberedoptions|ignore-remembered-args|ignore-remembered-arguments|ignore-remembered-options", + "Ignore Remembered Options for Uninstall - ignore the arguments and options used during install for Uninstall. Overrides the default feature '{0}' set to '{1}'. Available in 2.4.0+.".FormatWith(ApplicationParameters.Features.UseRememberedArgumentsForUninstalls, configuration.Features.UseRememberedArgumentsForUninstalls.ToString()), + option => + { + if (option != null) configuration.Features.UseRememberedArgumentsForUninstalls = false; + }) ; } diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index 02eaf34b6f..51a70394e9 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -251,8 +251,10 @@ private void AppendOutput(StringBuilder propertyValues, string append) // configuration set variables public string CacheLocation { get; set; } + public bool CacheLocationArgumentWasPassed { get; set; } public int CommandExecutionTimeoutSeconds { get; set; } + public bool CommandExecutionTimeoutSecondsArgumentWasPassed { get; set; } public int WebRequestTimeoutSeconds { get; set; } public string DefaultTemplateName { get; set; } @@ -555,6 +557,7 @@ public sealed class FeaturesConfiguration public bool ShowDownloadProgress { get; set; } public bool StopOnFirstPackageFailure { get; set; } public bool UseRememberedArgumentsForUpgrades { get; set; } + public bool UseRememberedArgumentsForUninstalls { get; set; } public bool IgnoreUnfoundPackagesOnUpgradeOutdated { get; set; } public bool SkipPackageUpgradesWhenNotInstalled { get; set; } public bool RemovePackageInformationOnUninstall { get; set; } diff --git a/src/chocolatey/infrastructure.app/services/INugetService.cs b/src/chocolatey/infrastructure.app/services/INugetService.cs index a7a3a30f35..b18eed288e 100644 --- a/src/chocolatey/infrastructure.app/services/INugetService.cs +++ b/src/chocolatey/infrastructure.app/services/INugetService.cs @@ -18,6 +18,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using chocolatey.infrastructure.app.configuration; +using chocolatey.infrastructure.app.domain; using chocolatey.infrastructure.results; namespace chocolatey.infrastructure.app.services @@ -67,6 +68,17 @@ public interface INugetService : ISourceRunner /// The configuration IEnumerable GetInstalledPackages(ChocolateyConfiguration config); + + /// + /// Gets the configuration from remembered arguments + /// + /// The original configuration. + /// The package information. + /// The command type + /// The modified configuration, so it can be used + ChocolateyConfiguration GetPackageConfigFromRememberedArguments(ChocolateyConfiguration config, + ChocolateyPackageInformation packageInfo, CommandNameType commandType = CommandNameType.Upgrade); + #pragma warning disable IDE0022, IDE1006 [Obsolete("This overload is deprecated and will be removed in v3.")] ConcurrentDictionary get_outdated(ChocolateyConfiguration config); diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index ea7f171255..3b121c976a 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -524,7 +524,7 @@ public virtual ConcurrentDictionary Install(ChocolateyCon if (packageNames.Count == 1) { var packageName = packageNames.DefaultIfEmpty(string.Empty).FirstOrDefault(); - if (packageName.EndsWith(NuGetConstants.PackageExtension) || packageName.EndsWith(PackagingConstants.ManifestExtension)) + if (packageName.EndsWith(NuGetConstants.PackageExtension, StringComparison.OrdinalIgnoreCase) || packageName.EndsWith(PackagingConstants.ManifestExtension, StringComparison.OrdinalIgnoreCase)) { this.Log().Warn(ChocolateyLoggers.Important, "DEPRECATION WARNING"); this.Log().Warn(InstallWithFilePathDeprecationMessage); @@ -534,7 +534,7 @@ public virtual ConcurrentDictionary Install(ChocolateyCon config.Sources = _fileSystem.GetDirectoryName(_fileSystem.GetFullPath(packageName)); - if (packageName.EndsWith(PackagingConstants.ManifestExtension)) + if (packageName.EndsWith(PackagingConstants.ManifestExtension, StringComparison.OrdinalIgnoreCase)) { packageNames.Add(_fileSystem.GetFilenameWithoutExtension(packageName)); @@ -578,7 +578,7 @@ public virtual ConcurrentDictionary Install(ChocolateyCon var installedPackage = allLocalPackages.FirstOrDefault(p => p.Name.IsEqualTo(packageName)); - if (Platform.GetPlatform() != PlatformType.Windows && !packageName.EndsWith(".template")) + if (Platform.GetPlatform() != PlatformType.Windows && !packageName.EndsWith(".template", StringComparison.OrdinalIgnoreCase)) { var logMessage = "{0} is not a supported package on non-Windows systems.{1}Only template packages are currently supported.".FormatWith(packageName, Environment.NewLine); this.Log().Warn(ChocolateyLoggers.Important, logMessage); @@ -1116,7 +1116,7 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon continue; } - SetConfigFromRememberedArguments(config, pkgInfo); + config = GetPackageConfigFromRememberedArguments(config, pkgInfo); var pathResolver = NugetCommon.GetPathResolver(_fileSystem); var nugetProject = new FolderNuGetProject(ApplicationParameters.PackagesLocation, pathResolver, NuGetFramework.AnyFramework); @@ -1254,12 +1254,12 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon var logMessage = "{0} is pinned. Skipping pinned package.".FormatWith(packageName); packageResult.Messages.Add(new ResultMessage(ResultType.Warn, logMessage)); packageResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, logMessage)); - + if (config.RegularOutput) { this.Log().Warn(ChocolateyLoggers.Important, logMessage); } - + continue; } else @@ -1271,7 +1271,7 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon { this.Log().Warn(ChocolateyLoggers.Important, logMessage); } - + config.PinPackage = true; } } @@ -1344,7 +1344,7 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon } var removedSources = new HashSet(); - + if (!config.UpgradeCommand.IgnorePinned) { RemovePinnedSourceDependencies(sourcePackageDependencyInfos, allLocalPackages); @@ -1780,15 +1780,11 @@ public virtual ConcurrentDictionary GetOutdated(Chocolate return outdatedPackages; } - /// - /// Sets the configuration for the package upgrade - /// - /// The configuration. - /// The package information. - /// The original unmodified configuration, so it can be reset after upgrade - protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) + [Obsolete("This method is deprecated and will be removed in v3.")] + protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo, CommandNameType commandType = CommandNameType.Upgrade) { - if (!config.Features.UseRememberedArgumentsForUpgrades || string.IsNullOrWhiteSpace(packageInfo.Arguments)) + if ((commandType == CommandNameType.Upgrade && !config.Features.UseRememberedArgumentsForUpgrades) || + (commandType == CommandNameType.Uninstall && !config.Features.UseRememberedArgumentsForUninstalls) || string.IsNullOrWhiteSpace(packageInfo.Arguments)) { return config; } @@ -1799,7 +1795,7 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco if (!ArgumentsUtility.SensitiveArgumentsProvided(packageArgumentsUnencrypted)) { sensitiveArgs = false; - this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding remembered arguments for upgrade: {1}".FormatWith(packageInfo.Package.Id, packageArgumentsUnencrypted.EscapeCurlyBraces())); + this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding remembered arguments: {1}".FormatWith(packageInfo.Package.Id, packageArgumentsUnencrypted.EscapeCurlyBraces())); } var packageArgumentsSplit = packageArgumentsUnencrypted.Split(new[] { " --" }, StringSplitOptions.RemoveEmptyEntries); @@ -1820,7 +1816,7 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco if (sensitiveArgs) { - this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding '{1}' to upgrade arguments. Values not shown due to detected sensitive arguments".FormatWith(packageInfo.Package.Id, optionName.EscapeCurlyBraces())); + this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding '{1}' to arguments. Values not shown due to detected sensitive arguments".FormatWith(packageInfo.Package.Id, optionName.EscapeCurlyBraces())); } packageArguments.Add("--{0}{1}".FormatWith(optionName, string.IsNullOrWhiteSpace(optionValue) ? string.Empty : "=" + optionValue)); } @@ -1830,6 +1826,16 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco ConfigurationOptions.OptionSet.Parse(packageArguments); // there may be overrides from the user running upgrade + if (!string.IsNullOrWhiteSpace(originalConfig.PackageParameters)) + { + config.PackageParameters = originalConfig.PackageParameters; + } + + if (!string.IsNullOrWhiteSpace(originalConfig.InstallArguments)) + { + config.InstallArguments = originalConfig.InstallArguments; + } + if (!string.IsNullOrWhiteSpace(originalConfig.SourceCommand.Username)) { config.SourceCommand.Username = originalConfig.SourceCommand.Username; @@ -1850,9 +1856,188 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco config.SourceCommand.CertificatePassword = originalConfig.SourceCommand.CertificatePassword; } + if (originalConfig.CacheLocationArgumentWasPassed && !string.IsNullOrWhiteSpace(originalConfig.CacheLocation)) + { + config.CacheLocation = originalConfig.CacheLocation; + } + + if (originalConfig.CommandExecutionTimeoutSecondsArgumentWasPassed) + { + config.CommandExecutionTimeoutSeconds = originalConfig.CommandExecutionTimeoutSeconds; + } + return originalConfig; } + /// + /// Gets the configuration from remembered arguments + /// + /// The original configuration. + /// The package information. + /// The command type + /// The modified configuration, so it can be used + public virtual ChocolateyConfiguration GetPackageConfigFromRememberedArguments(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo, CommandNameType commandType = CommandNameType.Upgrade) + { + if ((commandType == CommandNameType.Upgrade && !config.Features.UseRememberedArgumentsForUpgrades) || + (commandType == CommandNameType.Uninstall && !config.Features.UseRememberedArgumentsForUninstalls) || string.IsNullOrWhiteSpace(packageInfo.Arguments)) + { + return config; + } + + var packageArgumentsUnencrypted = packageInfo.Arguments.ContainsSafe(" --") && packageInfo.Arguments.ToStringSafe().Length > 4 ? packageInfo.Arguments : NugetEncryptionUtility.DecryptString(packageInfo.Arguments); + + var sensitiveArgs = ArgumentsUtility.SensitiveArgumentsProvided(packageArgumentsUnencrypted); + + var packageArgumentsSplit = packageArgumentsUnencrypted.Split(new[] { " --" }, StringSplitOptions.RemoveEmptyEntries); + var packageArguments = new List(); + foreach (var packageArgument in packageArgumentsSplit.OrEmpty()) + { + var packageArgumentSplit = packageArgument.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries); + var optionName = packageArgumentSplit[0].ToStringSafe(); + var optionValue = string.Empty; + if (packageArgumentSplit.Length == 2) + { + optionValue = packageArgumentSplit[1].ToStringSafe().UnquoteSafe(); + if (optionValue.StartsWith("'")) + { + optionValue.UnquoteSafe(); + } + } + + //Don't add install arguments during uninstall. We don't want a argument for the installer to be passed to the uninstaller. + if (string.Equals(optionName, "install-arguments", StringComparison.OrdinalIgnoreCase) && + commandType == CommandNameType.Uninstall) + { + continue; + } + + if (string.Equals(optionName, "override-argument", StringComparison.OrdinalIgnoreCase) && + commandType == CommandNameType.Uninstall) + { + continue; + } + + if (sensitiveArgs) + { + this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding '{1}' to arguments. Values not shown due to detected sensitive arguments".FormatWith(packageInfo.Package.Id, optionName.EscapeCurlyBraces())); + } + else + { + this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding '{1}' to arguments with a value of '{2}'".FormatWith(packageInfo.Package.Id, optionName.EscapeCurlyBraces(), optionValue.EscapeCurlyBraces())); + } + packageArguments.Add("--{0}{1}".FormatWith(optionName, string.IsNullOrWhiteSpace(optionValue) ? string.Empty : "=" + optionValue)); + } + + var originalConfig = config.DeepCopy(); + var rememberedOptionSet = new OptionSet(); + + rememberedOptionSet + .Add("pre|prerelease", + "Prerelease - Include Prereleases? Defaults to false.", + option => config.Prerelease = option != null) + .Add("i|ignoredependencies|ignore-dependencies", + "IgnoreDependencies - Ignore dependencies when installing package(s). Defaults to false.", + option => config.IgnoreDependencies = option != null) + .Add("x86|forcex86", + "ForceX86 - Force x86 (32bit) installation on 64 bit systems. Defaults to false.", + option => config.ForceX86 = option != null) + .Add("ia=|installargs=|install-args=|installarguments=|install-arguments=", + "InstallArguments - Install Arguments to pass to the native installer in the package. Defaults to unspecified.", + option => config.InstallArguments = option.UnquoteSafe()) + .Add("o|override|overrideargs|overridearguments|override-arguments", + "OverrideArguments - Should install arguments be used exclusively without appending to current package passed arguments? Defaults to false.", + option => config.OverrideArguments = option != null) + .Add("argsglobal|args-global|installargsglobal|install-args-global|applyargstodependencies|apply-args-to-dependencies|apply-install-arguments-to-dependencies", + "Apply Install Arguments To Dependencies - Should install arguments be applied to dependent packages? Defaults to false.", + option => config.ApplyInstallArgumentsToDependencies = option != null) + .Add("params=|parameters=|pkgparameters=|packageparameters=|package-parameters=", + "PackageParameters - Parameters to pass to the package. Defaults to unspecified.", + option => config.PackageParameters = option.UnquoteSafe()) + .Add("paramsglobal|params-global|packageparametersglobal|package-parameters-global|applyparamstodependencies|apply-params-to-dependencies|apply-package-parameters-to-dependencies", + "Apply Package Parameters To Dependencies - Should package parameters be applied to dependent packages? Defaults to false.", + option => config.ApplyPackageParametersToDependencies = option != null) + .Add("allowdowngrade|allow-downgrade", + "AllowDowngrade - Should an attempt at downgrading be allowed? Defaults to false.", + option => config.AllowDowngrade = option != null) + .Add("u=|user=", + "User - used with authenticated feeds. Defaults to empty.", + option => config.SourceCommand.Username = option.UnquoteSafe()) + .Add("p=|password=", + "Password - the user's password to the source. Defaults to empty.", + option => config.SourceCommand.Password = option.UnquoteSafe()) + .Add("cert=", + "Client certificate - PFX pathname for an x509 authenticated feeds. Defaults to empty. Available in 0.9.10+.", + option => config.SourceCommand.Certificate = option.UnquoteSafe()) + .Add("cp=|certpassword=", + "Certificate Password - the client certificate's password to the source. Defaults to empty. Available in 0.9.10+.", + option => config.SourceCommand.CertificatePassword = option.UnquoteSafe()) + .Add("timeout=|execution-timeout=", + "CommandExecutionTimeout (in seconds) - The time to allow a command to finish before timing out. Overrides the default execution timeout in the configuration of {0} seconds. '0' for infinite starting in 0.10.4.".FormatWith(config.CommandExecutionTimeoutSeconds.ToString()), + option => + { + var timeout = 0; + var timeoutString = option.UnquoteSafe(); + int.TryParse(timeoutString, out timeout); + if (timeout > 0 || timeoutString.IsEqualTo("0")) + { + config.CommandExecutionTimeoutSeconds = timeout; + } + }) + .Add("c=|cache=|cachelocation=|cache-location=", + "CacheLocation - Location for download cache, defaults to %TEMP% or value in chocolatey.config file.", + option => config.CacheLocation = option.UnquoteSafe()) + .Add("use-system-powershell", + "UseSystemPowerShell - Execute PowerShell using an external process instead of the built-in PowerShell host. Should only be used when internal host is failing. Available in 0.9.10+.", + option => config.Features.UsePowerShellHost = option != null); + + rememberedOptionSet.Parse(packageArguments); + + // there may be overrides from the user running upgrade + if (!string.IsNullOrWhiteSpace(originalConfig.PackageParameters)) + { + config.PackageParameters = originalConfig.PackageParameters; + } + + if (!string.IsNullOrWhiteSpace(originalConfig.InstallArguments)) + { + config.InstallArguments = originalConfig.InstallArguments; + } + + if (!string.IsNullOrWhiteSpace(originalConfig.SourceCommand.Username)) + { + config.SourceCommand.Username = originalConfig.SourceCommand.Username; + } + + if (!string.IsNullOrWhiteSpace(originalConfig.SourceCommand.Password)) + { + config.SourceCommand.Password = originalConfig.SourceCommand.Password; + } + + if (!string.IsNullOrWhiteSpace(originalConfig.SourceCommand.Certificate)) + { + config.SourceCommand.Certificate = originalConfig.SourceCommand.Certificate; + } + + if (!string.IsNullOrWhiteSpace(originalConfig.SourceCommand.CertificatePassword)) + { + config.SourceCommand.CertificatePassword = originalConfig.SourceCommand.CertificatePassword; + } + + if (originalConfig.CacheLocationArgumentWasPassed && !string.IsNullOrWhiteSpace(originalConfig.CacheLocation)) + { + config.CacheLocation = originalConfig.CacheLocation; + } + + if (originalConfig.CommandExecutionTimeoutSecondsArgumentWasPassed) + { + config.CommandExecutionTimeoutSeconds = originalConfig.CommandExecutionTimeoutSeconds; + } + + // We can't override switches because we don't know here if they were set on the command line + + return config; + } + private bool HasMissingDependency(PackageResult package, List allLocalPackages) { foreach (var dependency in package.PackageMetadata.DependencyGroups.SelectMany(d => d.Packages)) @@ -2425,6 +2610,8 @@ public virtual ConcurrentDictionary Uninstall(ChocolateyC continue; } + config = GetPackageConfigFromRememberedArguments(config, pkgInfo); + if (performAction) { var allPackagesIdentities = allLocalPackages.Where(p => !p.Identity.Equals(installedPackage)).Select(p => p.SearchMetadata.Identity).ToList();