From 45cd1a41423098589cb26b1bbec73f4365484ee2 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 27 Jan 2023 21:54:37 -0600 Subject: [PATCH 1/6] (#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 7e4251846..0f177f52b 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -571,7 +571,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); @@ -581,7 +581,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)); @@ -631,7 +631,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 dc243a811cedde2f0811aa9af575f9ba11efc085 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 27 Jan 2023 21:54:50 -0600 Subject: [PATCH 2/6] (#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 3d7be60ae..15d87c37b 100644 --- a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs +++ b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs @@ -420,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/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index 9954353c4..0f3314e96 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -252,8 +252,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 0f177f52b..2025d2512 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1968,6 +1968,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; @@ -1988,6 +1998,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 0907c0778a62802e84914f857e24276f2c14f497 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 27 Jan 2023 21:57:12 -0600 Subject: [PATCH 3/6] (#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 a7a3a30f3..9ea50e007 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 2025d2512..6821d2a4b 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1216,7 +1216,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); @@ -1354,12 +1354,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 @@ -1371,7 +1371,7 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon { this.Log().Warn(ChocolateyLoggers.Important, logMessage); } - + config.PinPackage = true; } } @@ -1453,7 +1453,7 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon } var removedSources = new HashSet(); - + if (!config.UpgradeCommand.IgnorePinned) { removedSources.AddRange(RemovePinnedSourceDependencies(sourcePackageDependencyInfos, allLocalPackages)); @@ -1937,12 +1937,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)) @@ -1968,16 +1963,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; @@ -2011,6 +2006,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 6391e051720834bb6e7e40d6b374d1ee9fc7827e Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 23 Sep 2022 13:53:58 -0500 Subject: [PATCH 4/6] (#2503) Export via serialization of class Instead of exporting via building an xml document manually, this creates a PackagesConfigFilePackageSetting and serializes that to create the xml document that is saved. This allows for usage of the same class as is used to read in packages.config files to export those files. The reason the various "Specified" members are added to the PackagesConfigFilePackageSetting class is so if an element is not set during export, it will not show up at all in the resulting serialized packages.config file. --- .../commands/ChocolateyExportCommand.cs | 32 ++-- .../PackagesConfigFilePackageSetting.cs | 181 ++++++++++++++++++ 2 files changed, 200 insertions(+), 13 deletions(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs index 11f956a1f..fd3f94d2d 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs @@ -20,6 +20,7 @@ using System.IO; using System.Text; using System.Xml; +using System.Xml.Serialization; using chocolatey.infrastructure.app.attributes; using chocolatey.infrastructure.commandline; using chocolatey.infrastructure.app.configuration; @@ -136,34 +137,39 @@ public void DryRun(ChocolateyConfiguration configuration) public void Run(ChocolateyConfiguration configuration) { - var packageResults = _nugetService.GetInstalledPackages(configuration); - var settings = new XmlWriterSettings { Indent = true, Encoding = new UTF8Encoding(false) }; + var installedPackages = _nugetService.GetInstalledPackages(configuration); + var xmlWriterSettings = new XmlWriterSettings { Indent = true, Encoding = new UTF8Encoding(false) }; FaultTolerance.TryCatchWithLoggingException( () => { + var packagesConfig = new PackagesConfigFileSettings(); + packagesConfig.Packages = new HashSet(); + using (var stringWriter = new StringWriter()) { - using (var xw = XmlWriter.Create(stringWriter, settings)) + using (var xw = XmlWriter.Create(stringWriter, xmlWriterSettings)) { - xw.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""); - xw.WriteStartElement("packages"); - - foreach (var packageResult in packageResults) + foreach (var packageResult in installedPackages) { - xw.WriteStartElement("package"); - xw.WriteAttributeString("id", packageResult.PackageMetadata.Id); + var packageElement = new PackagesConfigFilePackageSetting + { + Id = packageResult.PackageMetadata.Id + }; if (configuration.ExportCommand.IncludeVersionNumbers) { - xw.WriteAttributeString("version", packageResult.PackageMetadata.Version.ToString()); + packageElement.Version = packageResult.PackageMetadata.Version.ToString(); } - xw.WriteEndElement(); + packagesConfig.Packages.Add(packageElement); } - xw.WriteEndElement(); - xw.Flush(); + XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); + ns.Add("", ""); + + var packagesConfigSerializer = new XmlSerializer(typeof(PackagesConfigFileSettings)); + packagesConfigSerializer.Serialize(xw, packagesConfig, ns); } var fullOutputFilePath = _fileSystem.GetFullPath(configuration.ExportCommand.OutputFilePath); diff --git a/src/chocolatey/infrastructure.app/configuration/PackagesConfigFilePackageSetting.cs b/src/chocolatey/infrastructure.app/configuration/PackagesConfigFilePackageSetting.cs index 2344a34a6..61e4e0795 100644 --- a/src/chocolatey/infrastructure.app/configuration/PackagesConfigFilePackageSetting.cs +++ b/src/chocolatey/infrastructure.app/configuration/PackagesConfigFilePackageSetting.cs @@ -15,6 +15,7 @@ // limitations under the License. using System; +using System.ComponentModel; using System.Xml.Serialization; namespace chocolatey.infrastructure.app.configuration @@ -44,46 +45,130 @@ public sealed class PackagesConfigFilePackageSetting [XmlAttribute(AttributeName = "applyPackageParametersToDependencies")] public bool ApplyPackageParametersToDependencies { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ApplyPackageParametersToDependenciesSpecified + { + get { return ApplyPackageParametersToDependencies; } + } + [XmlAttribute(AttributeName = "applyInstallArgumentsToDependencies")] public bool ApplyInstallArgumentsToDependencies { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ApplyInstallArgumentsToDependenciesSpecified + { + get { return ApplyInstallArgumentsToDependencies; } + } + [XmlAttribute(AttributeName = "forceX86")] public bool ForceX86 { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ForceX86Specified + { + get { return ForceX86; } + } + [XmlAttribute(AttributeName = "ignoreDependencies")] public bool IgnoreDependencies { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool IgnoreDependenciesSpecified + { + get { return IgnoreDependencies; } + } + [XmlAttribute(AttributeName = "disabled")] public bool Disabled { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool DisabledSpecified + { + get { return Disabled; } + } + [XmlAttribute(AttributeName = "pinPackage")] public bool PinPackage { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool PinPackageSpecified + { + get { return PinPackage; } + } + [System.ComponentModel.DefaultValue(-1)] [XmlAttribute(AttributeName = "executionTimeout")] public int ExecutionTimeout { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ExecutionTimeoutSpecified + { + get { return ExecutionTimeout != 0; } + } + [XmlAttribute(AttributeName = "force")] public bool Force { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ForceSpecified + { + get { return Force; } + } + [XmlAttribute(AttributeName = "prerelease")] public bool Prerelease { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool PrereleaseSpecified + { + get { return Prerelease; } + } + [XmlAttribute(AttributeName = "overrideArguments")] public bool OverrideArguments { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool OverrideArgumentsSpecified + { + get { return OverrideArguments; } + } + [XmlAttribute(AttributeName = "notSilent")] public bool NotSilent { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool NotSilentSpecified + { + get { return NotSilent; } + } + [XmlAttribute(AttributeName = "allowDowngrade")] public bool AllowDowngrade { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool AllowDowngradeSpecified + { + get { return AllowDowngrade; } + } + [XmlAttribute(AttributeName = "forceDependencies")] public bool ForceDependencies { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ForceDependenciesSpecified + { + get { return ForceDependencies; } + } + [XmlAttribute(AttributeName = "skipAutomationScripts")] public bool SkipAutomationScripts { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool SkipAutomationScriptsSpecified + { + get { return SkipAutomationScripts; } + } + [XmlAttribute(AttributeName = "user")] public string User { get; set; } @@ -99,15 +184,39 @@ public sealed class PackagesConfigFilePackageSetting [XmlAttribute(AttributeName = "ignoreChecksums")] public bool IgnoreChecksums { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool IgnoreChecksumsSpecified + { + get { return IgnoreChecksums; } + } + [XmlAttribute(AttributeName = "allowEmptyChecksums")] public bool AllowEmptyChecksums { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool AllowEmptyChecksumsSpecified + { + get { return AllowEmptyChecksums; } + } + [XmlAttribute(AttributeName = "allowEmptyChecksumsSecure")] public bool AllowEmptyChecksumsSecure { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool AllowEmptyChecksumsSecureSpecified + { + get { return AllowEmptyChecksumsSecure; } + } + [XmlAttribute(AttributeName = "requireChecksums")] public bool RequireChecksums { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool RequireChecksumsSpecified + { + get { return RequireChecksums; } + } + [XmlAttribute(AttributeName = "downloadChecksum")] public string DownloadChecksum { get; set; } @@ -123,40 +232,112 @@ public sealed class PackagesConfigFilePackageSetting [XmlAttribute(AttributeName = "ignorePackageExitCodes")] public bool IgnorePackageExitCodes { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool IgnorePackageExitCodesSpecified + { + get { return IgnorePackageExitCodes; } + } + [XmlAttribute(AttributeName = "usePackageExitCodes")] public bool UsePackageExitCodes { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool UsePackageExitCodesSpecified + { + get { return UsePackageExitCodes; } + } + [XmlAttribute(AttributeName = "stopOnFirstFailure")] public bool StopOnFirstFailure { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool StopOnFirstFailureSpecified + { + get { return StopOnFirstFailure; } + } + [XmlAttribute(AttributeName = "exitWhenRebootDetected")] public bool ExitWhenRebootDetected { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ExitWhenRebootDetectedSpecified + { + get { return ExitWhenRebootDetected; } + } + [XmlAttribute(AttributeName = "ignoreDetectedReboot")] public bool IgnoreDetectedReboot { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool IgnoreDetectedRebootSpecified + { + get { return IgnoreDetectedReboot; } + } + [XmlAttribute(AttributeName = "disableRepositoryOptimizations")] public bool DisableRepositoryOptimizations { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool DisableRepositoryOptimizationsSpecified + { + get { return DisableRepositoryOptimizations; } + } + [XmlAttribute(AttributeName = "acceptLicense")] public bool AcceptLicense { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool AcceptLicenseSpecified + { + get { return AcceptLicense; } + } + [XmlAttribute(AttributeName = "confirm")] public bool Confirm { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool ConfirmSpecified + { + get { return Confirm; } + } + [XmlAttribute(AttributeName = "limitOutput")] public bool LimitOutput { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool LimitOutputSpecified + { + get { return LimitOutput; } + } + [XmlAttribute(AttributeName = "cacheLocation")] public string CacheLocation { get; set; } [XmlAttribute(AttributeName = "failOnStderr")] public bool FailOnStderr { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool FailOnStderrSpecified + { + get { return FailOnStderr; } + } + [XmlAttribute(AttributeName = "useSystemPowershell")] public bool UseSystemPowershell { get; set; } + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool UseSystemPowershellSpecified + { + get { return UseSystemPowershell; } + } + [XmlAttribute(AttributeName = "noProgress")] public bool NoProgress { get; set; } + + [XmlIgnore, EditorBrowsable(EditorBrowsableState.Never)] + public bool NoProgressSpecified + { + get { return NoProgress; } + } } } From 47e61ca32c3968b263bc8d5300471f9eeacb857f Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Tue, 9 Jan 2024 18:18:14 -0600 Subject: [PATCH 5/6] (#2503) Add ability to export remembered arguments This adds the --include-remembered-arguments option which is used to export any remembered arguments. It reuses the GetPackageConfigFromRememberedArguments method in the NugetService to read and parse the remembered arguments. --- .../helpers/ChocolateyTabExpansion.ps1 | 2 +- .../commands/ChocolateyExportCommandSpecs.cs | 18 +++++- .../commands/ChocolateyExportCommand.cs | 55 ++++++++++++++++++- .../configuration/ChocolateyConfiguration.cs | 1 + 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 b/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 index 1e81dc6aa..64b69ec68 100644 --- a/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 +++ b/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 @@ -56,7 +56,7 @@ $commandOptions = @{ config = "--name='' --value=''" feature = "--name=''" apikey = "--source='' --api-key='' --remove" - export = "--include-version-numbers --output-file-path=''" + export = "--include-version-numbers --output-file-path='' --include-remembered-arguments" template = "--name=''" cache = "--expired" rule = "--name=''" diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs index b5b1b7254..4ad9881de 100644 --- a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs @@ -37,16 +37,20 @@ public abstract class ChocolateyExportCommandSpecsBase : TinySpec protected Mock NugetService = new Mock(); protected Mock FileSystem = new Mock(); protected ChocolateyConfiguration Configuration = new ChocolateyConfiguration(); + protected Mock PackageInfoService = new Mock(); + protected Mock PackageService = new Mock(); public override void Context() { - Command = new ChocolateyExportCommand(NugetService.Object, FileSystem.Object); + Command = new ChocolateyExportCommand(NugetService.Object, FileSystem.Object, PackageInfoService.Object, PackageService.Object); } public void Reset() { NugetService.ResetCalls(); FileSystem.ResetCalls(); + PackageInfoService.ResetCalls(); + PackageService.ResetCalls(); } } @@ -104,6 +108,18 @@ public void Should_add_include_version_to_the_option_set() { _optionSet.Contains("include-version").Should().BeTrue(); } + + [Fact] + public void Should_add_include_arguments_to_the_option_set() + { + _optionSet.Contains("include-arguments").Should().BeTrue(); + } + + [Fact] + public void Should_add_include_remembered_arguments_to_the_option_set() + { + _optionSet.Contains("include-remembered-arguments").Should().BeTrue(); + } } public class When_handling_additional_argument_parsing : ChocolateyExportCommandSpecsBase diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs index fd3f94d2d..8005d471c 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs @@ -37,11 +37,19 @@ public class ChocolateyExportCommand : ICommand { private readonly INugetService _nugetService; private readonly IFileSystem _fileSystem; - - public ChocolateyExportCommand(INugetService nugetService, IFileSystem fileSystem) + private readonly IChocolateyPackageInformationService _packageInfoService; + private readonly IChocolateyPackageService _packageService; + + public ChocolateyExportCommand( + INugetService nugetService, + IFileSystem fileSystem, + IChocolateyPackageInformationService packageInfoService, + IChocolateyPackageService packageService) { _nugetService = nugetService; _fileSystem = fileSystem; + _packageInfoService = packageInfoService; + _packageService = packageService; } public void ConfigureArgumentParser(OptionSet optionSet, ChocolateyConfiguration configuration) @@ -53,6 +61,9 @@ public void ConfigureArgumentParser(OptionSet optionSet, ChocolateyConfiguration .Add("include-version-numbers|include-version", "Include Version Numbers - controls whether or not version numbers for each package appear in generated file. Defaults to false.", option => configuration.ExportCommand.IncludeVersionNumbers = option != null) + .Add("include-arguments|include-remembered-arguments", + "Include Remembered Arguments - controls whether or not remembered arguments for each package appear in generated file. Defaults to false. Available in 2.3.0+", + option => configuration.ExportCommand.IncludeRememberedPackageArguments = option != null) ; } @@ -96,12 +107,14 @@ choco export [] "chocolatey".Log().Info(@" choco export choco export --include-version-numbers + choco export --include-version-numbers --include-remembered-arguments choco export ""'c:\temp\packages.config'"" choco export ""'c:\temp\packages.config'"" --include-version-numbers choco export -o=""'c:\temp\packages.config'"" choco export -o=""'c:\temp\packages.config'"" --include-version-numbers choco export --output-file-path=""'c:\temp\packages.config'"" choco export --output-file-path=""'c:\temp\packages.config'"" --include-version-numbers + choco export --output-file-path=""""'c:\temp\packages.config'"""" --include-remembered-arguments NOTE: See scripting in the command reference (`choco -?`) for how to write proper scripts and integrations. @@ -132,7 +145,7 @@ public bool MayRequireAdminAccess() public void DryRun(ChocolateyConfiguration configuration) { - this.Log().Info("Export would have been with options: {0} Output File Path={1}{0} Include Version Numbers:{2}".FormatWith(Environment.NewLine, configuration.ExportCommand.OutputFilePath, configuration.ExportCommand.IncludeVersionNumbers)); + this.Log().Info("Export would have been with options: {0} Output File Path={1}{0} Include Version Numbers:{2}{0} Include Remembered Arguments: {3}".FormatWith(Environment.NewLine, configuration.ExportCommand.OutputFilePath, configuration.ExportCommand.IncludeVersionNumbers, configuration.ExportCommand.IncludeRememberedPackageArguments)); } public void Run(ChocolateyConfiguration configuration) @@ -140,6 +153,8 @@ public void Run(ChocolateyConfiguration configuration) var installedPackages = _nugetService.GetInstalledPackages(configuration); var xmlWriterSettings = new XmlWriterSettings { Indent = true, Encoding = new UTF8Encoding(false) }; + configuration.CreateBackup(); + FaultTolerance.TryCatchWithLoggingException( () => { @@ -162,6 +177,40 @@ public void Run(ChocolateyConfiguration configuration) packageElement.Version = packageResult.PackageMetadata.Version.ToString(); } + if (configuration.ExportCommand.IncludeRememberedPackageArguments) + { + var pkgInfo = _packageInfoService.Get(packageResult.PackageMetadata); + configuration.Features.UseRememberedArgumentsForUpgrades = true; + var rememberedConfig = _nugetService.GetPackageConfigFromRememberedArguments(configuration, pkgInfo); + + // Mirrors the arguments captured in ChocolateyPackageService.CaptureArguments() + if (configuration.Prerelease) packageElement.Prerelease = true; + if (configuration.IgnoreDependencies) packageElement.IgnoreDependencies = true; + if (configuration.ForceX86) packageElement.ForceX86 = true; + if (!string.IsNullOrWhiteSpace(configuration.InstallArguments)) packageElement.InstallArguments = configuration.InstallArguments; + if (configuration.OverrideArguments) packageElement.OverrideArguments = true; + if (configuration.ApplyInstallArgumentsToDependencies) packageElement.ApplyInstallArgumentsToDependencies = true; + if (!string.IsNullOrWhiteSpace(configuration.PackageParameters)) packageElement.PackageParameters = configuration.PackageParameters; + if (configuration.ApplyPackageParametersToDependencies) packageElement.ApplyPackageParametersToDependencies = true; + if (configuration.AllowDowngrade) packageElement.AllowDowngrade = true; + if (!string.IsNullOrWhiteSpace(configuration.SourceCommand.Username)) packageElement.User = configuration.SourceCommand.Username; + if (!string.IsNullOrWhiteSpace(configuration.SourceCommand.Password)) packageElement.Password = configuration.SourceCommand.Password; + if (!string.IsNullOrWhiteSpace(configuration.SourceCommand.Certificate)) packageElement.Cert = configuration.SourceCommand.Certificate; + if (!string.IsNullOrWhiteSpace(configuration.SourceCommand.CertificatePassword)) packageElement.CertPassword = configuration.SourceCommand.CertificatePassword; + // Arguments from the global options set + if (configuration.CommandExecutionTimeoutSeconds != ApplicationParameters.DefaultWaitForExitInSeconds) + { + packageElement.ExecutionTimeout = configuration.CommandExecutionTimeoutSeconds; + } + // This was discussed in the PR, and because it is potentially system specific, it should not be included in the exported file + // if (!string.IsNullOrWhiteSpace(configuration.CacheLocation)) packageElement.CacheLocation = configuration.CacheLocation; + // if (configuration.Features.FailOnStandardError) packageElement.FailOnStderr = true; + // if (!configuration.Features.UsePowerShellHost) packageElement.UseSystemPowershell = true; + + // Make sure to reset the configuration so as to be able to parse the next set of remembered arguments + configuration.RevertChanges(); + } + packagesConfig.Packages.Add(packageElement); } diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index 0f3314e96..7091e7b1d 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -734,6 +734,7 @@ public sealed class ProxyConfiguration public sealed class ExportCommandConfiguration { public bool IncludeVersionNumbers { get; set; } + public bool IncludeRememberedPackageArguments { get; set; } public string OutputFilePath { get; set; } } From 389b9b81f70c534ab34918da0f1cb248bd5a2582 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Thu, 24 Feb 2022 23:08:02 -0600 Subject: [PATCH 6/6] (#2603) Export pin status This adds the ability for the export command to include pins in the exported file. They will be exported if --include-arguments is specified, but can be excluded with --exclude-pins. --- .../helpers/ChocolateyTabExpansion.ps1 | 2 +- .../commands/ChocolateyExportCommandSpecs.cs | 6 ++++++ .../commands/ChocolateyExportCommand.cs | 16 +++++++++++++++- .../configuration/ChocolateyConfiguration.cs | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 b/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 index 64b69ec68..6f5c65f7d 100644 --- a/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 +++ b/src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1 @@ -56,7 +56,7 @@ $commandOptions = @{ config = "--name='' --value=''" feature = "--name=''" apikey = "--source='' --api-key='' --remove" - export = "--include-version-numbers --output-file-path='' --include-remembered-arguments" + export = "--include-version-numbers --output-file-path='' --include-remembered-arguments --exclude-pins" template = "--name=''" cache = "--expired" rule = "--name=''" diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs index 4ad9881de..73d49c028 100644 --- a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyExportCommandSpecs.cs @@ -120,6 +120,12 @@ public void Should_add_include_remembered_arguments_to_the_option_set() { _optionSet.Contains("include-remembered-arguments").Should().BeTrue(); } + + [Fact] + public void Should_add_exclude_pins_to_the_option_set() + { + _optionSet.Contains("exclude-pins").Should().BeTrue(); + } } public class When_handling_additional_argument_parsing : ChocolateyExportCommandSpecsBase diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs index 8005d471c..4b4cb5b32 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs @@ -64,6 +64,9 @@ public void ConfigureArgumentParser(OptionSet optionSet, ChocolateyConfiguration .Add("include-arguments|include-remembered-arguments", "Include Remembered Arguments - controls whether or not remembered arguments for each package appear in generated file. Defaults to false. Available in 2.3.0+", option => configuration.ExportCommand.IncludeRememberedPackageArguments = option != null) + .Add("exclude-pins", + "Exclude Pins - controls whether or not pins are included. Only applies if remembered arguments are exported. Defaults to false. Available in 2.4.0+", + option => configuration.ExportCommand.ExcludePins = option != null) ; } @@ -108,6 +111,7 @@ choco export [] choco export choco export --include-version-numbers choco export --include-version-numbers --include-remembered-arguments + choco export --include-remembered-arguments --exclude-pins choco export ""'c:\temp\packages.config'"" choco export ""'c:\temp\packages.config'"" --include-version-numbers choco export -o=""'c:\temp\packages.config'"" @@ -145,7 +149,12 @@ public bool MayRequireAdminAccess() public void DryRun(ChocolateyConfiguration configuration) { - this.Log().Info("Export would have been with options: {0} Output File Path={1}{0} Include Version Numbers:{2}{0} Include Remembered Arguments: {3}".FormatWith(Environment.NewLine, configuration.ExportCommand.OutputFilePath, configuration.ExportCommand.IncludeVersionNumbers, configuration.ExportCommand.IncludeRememberedPackageArguments)); + this.Log().Info("Export would have been with options: {0} Output File Path={1}{0} Include Version Numbers:{2}{0} Include Remembered Arguments: {3}{0} Exclude Pins: {4}".FormatWith( + Environment.NewLine, + configuration.ExportCommand.OutputFilePath, + configuration.ExportCommand.IncludeVersionNumbers, + configuration.ExportCommand.IncludeRememberedPackageArguments, + configuration.ExportCommand.ExcludePins)); } public void Run(ChocolateyConfiguration configuration) @@ -207,6 +216,11 @@ public void Run(ChocolateyConfiguration configuration) // if (configuration.Features.FailOnStandardError) packageElement.FailOnStderr = true; // if (!configuration.Features.UsePowerShellHost) packageElement.UseSystemPowershell = true; + if (!configuration.ExportCommand.ExcludePins && pkgInfo.IsPinned) + { + xw.WriteAttributeString("pinPackage", "true"); + } + // Make sure to reset the configuration so as to be able to parse the next set of remembered arguments configuration.RevertChanges(); } diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index 7091e7b1d..999795c18 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -735,6 +735,7 @@ public sealed class ExportCommandConfiguration { public bool IncludeVersionNumbers { get; set; } public bool IncludeRememberedPackageArguments { get; set; } + public bool ExcludePins { get; set; } public string OutputFilePath { get; set; } }