From edd1f23054701874130729186979335ab6348751 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 27 Jan 2023 21:54:37 -0600 Subject: [PATCH 1/7] (#508) Make package id comparisons case insensitive This helps ensure that package IDs are handled in a case insensitive manner. --- src/chocolatey/infrastructure.app/services/NugetService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index ea7f171255..7b4170eab0 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); From 2c37c9a78d194798636f77ca3ab8b1a53df23a87 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 27 Jan 2023 21:54:50 -0600 Subject: [PATCH 2/7] (#2761) Allow overriding remembered arguments This allows overriding of remembered package parameters, install arguments, cache location and execution timeout during upgrade. So a user can pass in different package parameters or arguments without having to completely reinstall the package or turn off remembered arguments. Switch arguments cannot be checked, because the lack of a switch normally would mean that they are just relying on the remembered args to remember it, so there is no way to determine if an override of the remembered args is appropriate. --- .../builders/ConfigurationBuilder.cs | 7 ++++++- .../configuration/ChocolateyConfiguration.cs | 2 ++ .../services/NugetService.cs | 20 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs index 8dd3295af0..7b130e6265 100644 --- a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs +++ b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs @@ -419,11 +419,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/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index 02eaf34b6f..bfbaf43ff0 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; } diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index 7b4170eab0..d7ba9154e9 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1830,6 +1830,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,6 +1860,16 @@ 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; } From 85ab9168ac6e2a667a0876caacaa5704f6e4dec9 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 27 Jan 2023 21:57:12 -0600 Subject: [PATCH 3/7] (#2886) Switch remembered args to only change local configuration This adds a new method, GetPackageConfigFromRememberedArguments which is similar to SetConfigFromRememberedArguments, but operates using a different method. First, a OptionSet is set up, so only the config that is passed in is modified, instead of the config that the global options parser was set with with. Second, it returns the modified configuration instead of the original configuration, because it is the local configuration being modified. Third, it has a more general name and changes log messages to be more general, so it later can more easily be reused for uninstall and export. This change fixes remembered arguments when Chocolatey is used as a library, like in ChocolateyGUI, where the config that is passed to the install_run method is not necessarily the same config object that was used to set up the global argument parser. The downside of using a new commandline parser is that it opens up the possibility of drift between the upgrade/global arguments and this added parser. However, this is not an issue because the format of the saved arguments is known, and any added arguments there would not work without being added here as well, which would be picked up during development. --- .../services/INugetService.cs | 11 ++ .../services/NugetService.cs | 178 ++++++++++++++++-- 2 files changed, 175 insertions(+), 14 deletions(-) diff --git a/src/chocolatey/infrastructure.app/services/INugetService.cs b/src/chocolatey/infrastructure.app/services/INugetService.cs index a7a3a30f35..9ea50e0078 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,16 @@ public interface INugetService : ISourceRunner /// The configuration IEnumerable GetInstalledPackages(ChocolateyConfiguration config); + + /// + /// Gets the configuration from remembered arguments + /// + /// The original configuration. + /// The package information. + /// The modified configuration, so it can be used + ChocolateyConfiguration GetPackageConfigFromRememberedArguments(ChocolateyConfiguration config, + ChocolateyPackageInformation packageInfo); + #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 d7ba9154e9..1f8caf3f00 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -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,12 +1780,7 @@ 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 + [Obsolete("This method is deprecated and will be removed in v3.")] protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) { if (!config.Features.UseRememberedArgumentsForUpgrades || string.IsNullOrWhiteSpace(packageInfo.Arguments)) @@ -1830,16 +1825,16 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco ConfigurationOptions.OptionSet.Parse(packageArguments); // there may be overrides from the user running upgrade - if (!string.IsNullOrWhiteSpace(originalConfig.PackageParameters)) + 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; @@ -1873,6 +1868,161 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco return originalConfig; } + /// + /// Gets the configuration from remembered arguments + /// + /// The original configuration. + /// The package information. + /// The modified configuration, so it can be used + public virtual ChocolateyConfiguration GetPackageConfigFromRememberedArguments(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) + { + if (!config.Features.UseRememberedArgumentsForUpgrades || string.IsNullOrWhiteSpace(packageInfo.Arguments)) + { + return config; + } + + var packageArgumentsUnencrypted = packageInfo.Arguments.ContainsSafe(" --") && packageInfo.Arguments.ToStringSafe().Length > 4 ? packageInfo.Arguments : NugetEncryptionUtility.DecryptString(packageInfo.Arguments); + + var sensitiveArgs = true; + if (!ArgumentsUtility.SensitiveArgumentsProvided(packageArgumentsUnencrypted)) + { + sensitiveArgs = false; + this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding remembered arguments: {1}".FormatWith(packageInfo.Package.Id, packageArgumentsUnencrypted.EscapeCurlyBraces())); + } + + 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(); + } + } + + 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())); + } + 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)) From 1f484ed3a56e4b7ffccc16620a832d20c66b6518 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 9 Mar 2022 23:55:22 -0600 Subject: [PATCH 4/7] (#1479) Rework set package config method This brings out the functionality from the set_package_config_for_upgrade method to a more generic name, and adds in another parameter to prepare for setting remembered args for uninstall as well as upgrade. It also updates the logging and comments to make them generic for both upgrades and uninstalls. An alias/forwarding method is added for backwards compatibility. --- .../infrastructure.app/services/INugetService.cs | 3 ++- .../infrastructure.app/services/NugetService.cs | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/chocolatey/infrastructure.app/services/INugetService.cs b/src/chocolatey/infrastructure.app/services/INugetService.cs index 9ea50e0078..b18eed288e 100644 --- a/src/chocolatey/infrastructure.app/services/INugetService.cs +++ b/src/chocolatey/infrastructure.app/services/INugetService.cs @@ -74,9 +74,10 @@ public interface INugetService : ISourceRunner /// /// The original configuration. /// The package information. + /// The command type /// The modified configuration, so it can be used ChocolateyConfiguration GetPackageConfigFromRememberedArguments(ChocolateyConfiguration config, - ChocolateyPackageInformation packageInfo); + ChocolateyPackageInformation packageInfo, CommandNameType commandType = CommandNameType.Upgrade); #pragma warning disable IDE0022, IDE1006 [Obsolete("This overload is deprecated and will be removed in v3.")] diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index 1f8caf3f00..af758ff5a9 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1781,9 +1781,10 @@ public virtual ConcurrentDictionary GetOutdated(Chocolate } [Obsolete("This method is deprecated and will be removed in v3.")] - protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) + 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; } @@ -1794,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); @@ -1815,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)); } @@ -1873,10 +1874,12 @@ protected virtual ChocolateyConfiguration SetConfigFromRememberedArguments(Choco /// /// 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) + public virtual ChocolateyConfiguration GetPackageConfigFromRememberedArguments(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; } From f65c262f2ce5cd26c6d8987ed55d2ae1429f38fd Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 9 Mar 2022 23:54:33 -0600 Subject: [PATCH 5/7] (#1479) Add UseRememberedArgumentsForUninstalls feature Similar to the UseRememberedArgumentsForUpgrade feature, this will be used to toggle if the remembered arguments are used during uninstall. --- src/chocolatey/infrastructure.app/ApplicationParameters.cs | 1 + .../infrastructure.app/builders/ConfigurationBuilder.cs | 1 + .../infrastructure.app/configuration/ChocolateyConfiguration.cs | 1 + 3 files changed, 3 insertions(+) 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 7b130e6265..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? "); diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index bfbaf43ff0..51a70394e9 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -557,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; } From f6227e7abe6937044c736ce7522e6485907ba9b2 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 9 Mar 2022 23:56:31 -0600 Subject: [PATCH 6/7] (#1479) Implement using remembed arguments for uninstalls This adds the ability for the remembered argument to be reused for uninstalls. It can be controlled via the userememberedargs and ignorerememberedargs arguments, or via the previously added feature. --- .../commands/ChocolateyUninstallCommand.cs | 12 +++++++++ .../services/NugetService.cs | 26 ++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) 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/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index af758ff5a9..3b121c976a 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1886,12 +1886,7 @@ public virtual ChocolateyConfiguration GetPackageConfigFromRememberedArguments(C var packageArgumentsUnencrypted = packageInfo.Arguments.ContainsSafe(" --") && packageInfo.Arguments.ToStringSafe().Length > 4 ? packageInfo.Arguments : NugetEncryptionUtility.DecryptString(packageInfo.Arguments); - var sensitiveArgs = true; - if (!ArgumentsUtility.SensitiveArgumentsProvided(packageArgumentsUnencrypted)) - { - sensitiveArgs = false; - this.Log().Debug(ChocolateyLoggers.Verbose, "{0} - Adding remembered arguments: {1}".FormatWith(packageInfo.Package.Id, packageArgumentsUnencrypted.EscapeCurlyBraces())); - } + var sensitiveArgs = ArgumentsUtility.SensitiveArgumentsProvided(packageArgumentsUnencrypted); var packageArgumentsSplit = packageArgumentsUnencrypted.Split(new[] { " --" }, StringSplitOptions.RemoveEmptyEntries); var packageArguments = new List(); @@ -1909,10 +1904,27 @@ public virtual ChocolateyConfiguration GetPackageConfigFromRememberedArguments(C } } + //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)); } @@ -2598,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(); From 75298e2b2a14c5f69794c11f807778beb88718d4 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Thu, 10 Mar 2022 17:42:03 -0600 Subject: [PATCH 7/7] (#1479) Add tests for remembered args args for uninstall --- .../ChocolateyUninstallCommandSpecs.cs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) 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