From de61b1d1a19a7edd8e9b38921b3b29e54d55ac15 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Sun, 3 Oct 2021 20:05:33 +0100 Subject: [PATCH 1/4] (maint) Remove unnecessary whitespace --- .../services/TemplateServiceSpecs.cs | 8 ++++---- .../infrastructure.app/services/TemplateService.cs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs index 400a57af0..4ba448ac1 100644 --- a/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs @@ -1,13 +1,13 @@ // Copyright © 2017 - 2021 Chocolatey Software, Inc // Copyright © 2011 - 2017 RealDimensions Software, LLC -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// +// // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/src/chocolatey/infrastructure.app/services/TemplateService.cs b/src/chocolatey/infrastructure.app/services/TemplateService.cs index f56df592c..85964a0bb 100644 --- a/src/chocolatey/infrastructure.app/services/TemplateService.cs +++ b/src/chocolatey/infrastructure.app/services/TemplateService.cs @@ -1,13 +1,13 @@ // Copyright © 2017 - 2021 Chocolatey Software, Inc // Copyright © 2011 - 2017 RealDimensions Software, LLC -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// +// // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,7 +31,7 @@ public class TemplateService : ITemplateService { private readonly UTF8Encoding utf8WithoutBOM = new UTF8Encoding(false); private readonly IFileSystem _fileSystem; - private readonly IList _templateBinaryExtensions = new List { + private readonly IList _templateBinaryExtensions = new List { ".exe", ".msi", ".msu", ".msp", ".mst", ".7z", ".zip", ".rar", ".gz", ".iso", ".tar", ".sfx", ".dmg", @@ -122,7 +122,7 @@ public void generate(ChocolateyConfiguration configuration) if (!_fileSystem.directory_exists(templatePath)) throw new ApplicationException("Unable to find path to requested template '{0}'. Path should be '{1}'".format_with(configuration.NewCommand.TemplateName, templatePath)); this.Log().Info(configuration.QuietOutput ? logger : ChocolateyLoggers.Important, "Generating package from custom template at '{0}'.".format_with(templatePath)); - + // Create directory structure from template so as to include empty directories foreach (var directory in _fileSystem.get_directories(templatePath, "*.*", SearchOption.AllDirectories)) { From dafae0f541964c6ce5a92dd38ec8e2f0ba9e53cb Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Sun, 3 Oct 2021 20:07:56 +0100 Subject: [PATCH 2/4] (#2377) Add new config value DefaultTemplateName This will be used to allow the user to control which template should be used by default. While it is possible to allow the user to override the default template files, this gives them a little bit more control, to specify via configuration which template they want to use by default. --- 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 6afa6b0fb..ce0bcdccd 100644 --- a/src/chocolatey/infrastructure.app/ApplicationParameters.cs +++ b/src/chocolatey/infrastructure.app/ApplicationParameters.cs @@ -174,6 +174,7 @@ public static class ConfigSettings public static readonly string ProxyBypassOnLocal = "proxyBypassOnLocal"; public static readonly string WebRequestTimeoutSeconds = "webRequestTimeoutSeconds"; public static readonly string UpgradeAllExceptions = "upgradeAllExceptions"; + public static readonly string DefaultTemplateName = "defaultTemplateName"; } public static class Features diff --git a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs index 042d662c9..7956336e7 100644 --- a/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs +++ b/src/chocolatey/infrastructure.app/builders/ConfigurationBuilder.cs @@ -254,6 +254,7 @@ private static void set_config_items(ChocolateyConfiguration config, ConfigFileS config.Proxy.BypassList = set_config_item(ApplicationParameters.ConfigSettings.ProxyBypassList, configFileSettings, string.Empty, "Optional proxy bypass list. Comma separated. Available in 0.10.4+."); config.Proxy.BypassOnLocal = set_config_item(ApplicationParameters.ConfigSettings.ProxyBypassOnLocal, configFileSettings, "true", "Bypass proxy for local connections. Available in 0.10.4+.").is_equal_to(bool.TrueString); config.UpgradeCommand.PackageNamesToSkip = set_config_item(ApplicationParameters.ConfigSettings.UpgradeAllExceptions, configFileSettings, string.Empty, "A comma-separated list of package names that should not be upgraded when running `choco upgrade all'. Defaults to empty. Available in 0.10.14+."); + config.DefaultTemplateName = set_config_item(ApplicationParameters.ConfigSettings.DefaultTemplateName, configFileSettings, string.Empty, "Default template name used when running 'choco new' command. Available in 0.12.0+."); } private static string set_config_item(string configName, ConfigFileSettings configFileSettings, string defaultValue, string description, bool forceSettingValue = false) diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index d3c3e5188..c4ec78233 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -146,6 +146,7 @@ private void append_output(StringBuilder propertyValues, string append) public bool ContainsLegacyPackageInstalls { get; set; } public int CommandExecutionTimeoutSeconds { get; set; } public int WebRequestTimeoutSeconds { get; set; } + public string DefaultTemplateName { get; set; } /// /// One or more source locations set by configuration or by command line. Separated by semi-colon From defb7d31448e3ad8f5e728ab5daafd1e6fa9cc25 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Sun, 3 Oct 2021 20:10:02 +0100 Subject: [PATCH 3/4] (#2377) Use defaultTemplateName if set If the defaultTemplateName configuration value is set, and the user hasn't specified a template name at the command line, check to see whether a template exists with that name. If it does, use this as the template when generating the new package. Given that the default value for the new defaultTemplateName configuration value is an empty string, if the user is directly overriding the default template files folder, this overriding will still take place. Also take into consideration the usage of the --built-in command line option. If this is set, make sure to respect it. The order of precedence is the following: 1. choco new --template=name 2. choco new --built-in 3. choco config defaultTemplateName 4. Manually created files in $env:chocolateyinstall\templates\default 5. Fall back onto the built-in template. --- .../services/TemplateService.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/chocolatey/infrastructure.app/services/TemplateService.cs b/src/chocolatey/infrastructure.app/services/TemplateService.cs index 85964a0bb..5c4cd57e7 100644 --- a/src/chocolatey/infrastructure.app/services/TemplateService.cs +++ b/src/chocolatey/infrastructure.app/services/TemplateService.cs @@ -102,6 +102,27 @@ public void generate(ChocolateyConfiguration configuration) this.Log().Debug(() => " {0}={1}".format_with(additionalProperty.Key, additionalProperty.Value)); } + // Attempt to set the name of the template that will be used to generate the new package + // If no template name has been passed at the command line, check to see if there is a defaultTemplateName set in the + // chocolatey.config file. If there is, and this template exists on disk, use it. + // Otherwise, revert to the built in default template. + // In addition, if the command line option to use the built-in template has been set, respect that + // and use the built in template. + var defaultTemplateName = configuration.DefaultTemplateName; + if (string.IsNullOrWhiteSpace(configuration.NewCommand.TemplateName) && !string.IsNullOrWhiteSpace(defaultTemplateName) && !configuration.NewCommand.UseOriginalTemplate) + { + var defaultTemplateNameLocation = _fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, defaultTemplateName); + if (!_fileSystem.directory_exists(defaultTemplateNameLocation)) + { + this.Log().Warn(() => "defaultTemplateName configuration value has been set to '{0}', but no template with that name exists in '{1}'. Reverting to default template.".format_with(defaultTemplateName, ApplicationParameters.TemplatesLocation)); + } + else + { + this.Log().Debug(() => "Setting TemplateName to '{0}'".format_with(defaultTemplateName)); + configuration.NewCommand.TemplateName = defaultTemplateName; + } + } + var defaultTemplateOverride = _fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, "default"); if (string.IsNullOrWhiteSpace(configuration.NewCommand.TemplateName) && (!_fileSystem.directory_exists(defaultTemplateOverride) || configuration.NewCommand.UseOriginalTemplate)) { From fd5b8e904280c58cd639d06c80c7014f80551b56 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Mon, 11 Oct 2021 21:14:11 +0100 Subject: [PATCH 4/4] (#2377) Add unit tests Unit tests have been added to exercise the generate method of the TemplateService to ensure that the template name that is used matches the configured value. - If option is set at the command line, it should win, even if there is a default value in the chocolatey.config file. - If default value is set in chocolatey.config file but path doesn't exist, should use null value - If default value is set in chocolatey.config file and path exists, should be set to this template value - If --built-in option is set, this should override default value in chocolatey.config file --- .../services/TemplateServiceSpecs.cs | 295 ++++++++++++++++++ 1 file changed, 295 insertions(+) diff --git a/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs index 4ba448ac1..1cdf4028a 100644 --- a/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs @@ -21,11 +21,13 @@ namespace chocolatey.tests.infrastructure.app.services using System.IO; using System.Linq; using System.Text; + using chocolatey.infrastructure.app; using chocolatey.infrastructure.app.configuration; using chocolatey.infrastructure.app.services; using chocolatey.infrastructure.app.templates; using chocolatey.infrastructure.filesystem; using Moq; + using NUnit.Framework; using Should; public class TemplateServiceSpecs @@ -529,5 +531,298 @@ public void should_generate_all_files_and_directories_even_with_outputdirectory( MockLogger.MessagesFor(LogLevel.Info).Last().ShouldEqual(string.Format(@"Successfully generated Bob package specification files{0} at 'c:\packages\Bob'", Environment.NewLine)); } } + + public class when_generate_is_called_with_defaulttemplatename_in_configuration_but_template_folder_doesnt_exist : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + + public override void Context() + { + base.Context(); + + fileSystem.Setup(x => x.get_current_directory()).Returns("c:\\chocolatey"); + fileSystem.Setup(x => x.combine_paths(It.IsAny(), It.IsAny())) + .Returns((string a, string[] b) => { return a + "\\" + b[0]; }); + + config.NewCommand.Name = "Bob"; + config.DefaultTemplateName = "msi"; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_null_value_for_template() + { + because(); + + config.NewCommand.TemplateName.ShouldBeNull(); + } + } + + public class when_generate_is_called_with_defaulttemplatename_in_configuration_and_template_folder_exists : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private string verifiedDirectoryPath; + + public override void Context() + { + base.Context(); + + fileSystem.Setup(x => x.get_current_directory()).Returns("c:\\chocolatey"); + fileSystem.Setup(x => x.combine_paths(It.IsAny(), It.IsAny())) + .Returns((string a, string[] b) => { return a + "\\" + b[0]; }); + fileSystem.Setup(x => x.directory_exists(Path.Combine(ApplicationParameters.TemplatesLocation, "msi"))).Returns( + x => + { + verifiedDirectoryPath = x; + return true; + }); + + config.NewCommand.Name = "Bob"; + config.DefaultTemplateName = "msi"; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_template_name_from_configuration() + { + because(); + + config.NewCommand.TemplateName.ShouldEqual("msi"); + } + } + + public class when_generate_is_called_with_defaulttemplatename_in_configuration_and_template_name_option_set : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private string verifiedDirectoryPath; + + public override void Context() + { + base.Context(); + + fileSystem.Setup(x => x.get_current_directory()).Returns("c:\\chocolatey"); + fileSystem.Setup(x => x.combine_paths(It.IsAny(), It.IsAny())) + .Returns((string a, string[] b) => { return a + "\\" + b[0]; }); + fileSystem.Setup(x => x.directory_exists(Path.Combine(ApplicationParameters.TemplatesLocation, "zip"))).Returns( + x => + { + verifiedDirectoryPath = x; + return true; + }); + + config.NewCommand.Name = "Bob"; + config.NewCommand.TemplateName = "zip"; + config.DefaultTemplateName = "msi"; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_template_name_from_command_line_option() + { + because(); + + config.NewCommand.TemplateName.ShouldEqual("zip"); + } + } + + public class when_generate_is_called_with_built_in_option_set : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private string verifiedDirectoryPath; + + public override void Context() + { + base.Context(); + + config.NewCommand.Name = "Bob"; + config.NewCommand.UseOriginalTemplate = true; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_null_value_for_template() + { + because(); + + config.NewCommand.TemplateName.ShouldBeNull(); + } + } + + public class when_generate_is_called_with_built_in_option_set_and_defaulttemplate_in_configuration : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private string verifiedDirectoryPath; + + public override void Context() + { + base.Context(); + + config.NewCommand.Name = "Bob"; + config.NewCommand.UseOriginalTemplate = true; + config.DefaultTemplateName = "msi"; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_null_value_for_template() + { + because(); + + config.NewCommand.TemplateName.ShouldBeNull(); + } + } + + public class when_generate_is_called_with_built_in_option_set_and_template_name_option_set_and_template_folder_exists : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private string verifiedDirectoryPath; + + public override void Context() + { + base.Context(); + + fileSystem.Setup(x => x.get_current_directory()).Returns("c:\\chocolatey"); + fileSystem.Setup(x => x.combine_paths(It.IsAny(), It.IsAny())) + .Returns((string a, string[] b) => { return a + "\\" + b[0]; }); + fileSystem.Setup(x => x.directory_exists(Path.Combine(ApplicationParameters.TemplatesLocation, "zip"))).Returns( + x => + { + verifiedDirectoryPath = x; + return true; + }); + + config.NewCommand.Name = "Bob"; + config.NewCommand.TemplateName = "zip"; + config.NewCommand.UseOriginalTemplate = true; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_template_name_from_command_line_option() + { + because(); + + config.NewCommand.TemplateName.ShouldEqual("zip"); + } + } + + public class when_generate_is_called_with_built_in_option_set_and_template_name_option_set_and_defaulttemplatename_set_and_template_folder_exists : TemplateServiceSpecsBase + { + private Action because; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private string verifiedDirectoryPath; + + public override void Context() + { + base.Context(); + + fileSystem.Setup(x => x.get_current_directory()).Returns("c:\\chocolatey"); + fileSystem.Setup(x => x.combine_paths(It.IsAny(), It.IsAny())) + .Returns((string a, string[] b) => { return a + "\\" + b[0]; }); + fileSystem.Setup(x => x.directory_exists(Path.Combine(ApplicationParameters.TemplatesLocation, "zip"))).Returns( + x => + { + verifiedDirectoryPath = x; + return true; + }); + + config.NewCommand.Name = "Bob"; + config.NewCommand.TemplateName = "zip"; + config.DefaultTemplateName = "msi"; + config.NewCommand.UseOriginalTemplate = true; + } + + public override void Because() + { + because = () => service.generate(config); + } + + public override void BeforeEachSpec() + { + MockLogger.reset(); + } + + [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] + public void should_use_template_name_from_command_line_option() + { + because(); + + config.NewCommand.TemplateName.ShouldEqual("zip"); + } + } } }