diff --git a/src/chocolatey/chocolatey.csproj b/src/chocolatey/chocolatey.csproj
index eea25ebe2d..1301daa138 100644
--- a/src/chocolatey/chocolatey.csproj
+++ b/src/chocolatey/chocolatey.csproj
@@ -113,6 +113,8 @@
Properties\SolutionVersion.cs
+
+
diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyTemplateCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyTemplateCommand.cs
new file mode 100644
index 0000000000..110c5bf10b
--- /dev/null
+++ b/src/chocolatey/infrastructure.app/commands/ChocolateyTemplateCommand.cs
@@ -0,0 +1,157 @@
+// 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.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace chocolatey.infrastructure.app.commands
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using attributes;
+ using commandline;
+ using configuration;
+ using domain;
+ using infrastructure.commands;
+ using logging;
+ using services;
+ using templates;
+
+ [CommandFor("template", "get information about installed templates")]
+ [CommandFor("templates", "get information about installed templates (alias for template)")]
+ public class ChocolateyTemplateCommand : ICommand
+ {
+ private readonly ITemplateService _templateService;
+
+ public ChocolateyTemplateCommand(ITemplateService templateService)
+ {
+ _templateService = templateService;
+ }
+
+ public void configure_argument_parser(OptionSet optionSet, ChocolateyConfiguration configuration)
+ {
+ optionSet
+ .Add("n=|name=",
+ "The name of the template to get information about.",
+ option => configuration.TemplateCommand.Name = option.remove_surrounding_quotes().ToLower());
+ // TODO Allow for templates from external path? If PR 1477 is merged
+ }
+
+ public virtual void handle_additional_argument_parsing(IList unparsedArguments, ChocolateyConfiguration configuration)
+ {
+ // don't set configuration.Input or it will be passed to list
+
+ if (unparsedArguments.Count > 1)
+ {
+ throw new ApplicationException("A single template command must be listed. Please see the help menu for those commands");
+ }
+
+ var command = TemplateCommandType.unknown;
+ string unparsedCommand = unparsedArguments.DefaultIfEmpty(string.Empty).FirstOrDefault();
+ Enum.TryParse(unparsedCommand, true, out command);
+
+ if (command == TemplateCommandType.unknown)
+ {
+ if (!string.IsNullOrWhiteSpace(unparsedCommand)) this.Log().Warn("Unknown command {0}. Setting to list.".format_with(unparsedCommand));
+ command = TemplateCommandType.list;
+ }
+
+ configuration.TemplateCommand.Command = command;
+ }
+
+ public virtual void handle_validation(ChocolateyConfiguration configuration)
+ {
+ if (configuration.TemplateCommand.Command != TemplateCommandType.list && string.IsNullOrWhiteSpace(configuration.TemplateCommand.Name))
+ {
+ throw new ApplicationException("When specifying the subcommand '{0}', you must also specify --name.".format_with(configuration.TemplateCommand.Command.to_string()));
+ }
+ }
+
+ public virtual void help_message(ChocolateyConfiguration configuration)
+ {
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Template Command");
+ "chocolatey".Log().Info(@"
+List information installed templates.
+
+Both manually installed templates and templates installed via
+ .template packages are displayed.");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Usage");
+ "chocolatey".Log().Info(@"
+ choco pin [list]|info []");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Examples");
+ "chocolatey".Log().Info(@"
+ choco template
+ choco templates
+ choco template list
+ choco template info --name msi
+ choco template list --reduce-output
+ choco template list --verbose
+
+NOTE: See scripting in the command reference (`choco -?`) for how to
+ write proper scripts and integrations.
+
+");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Exit Codes");
+ "chocolatey".Log().Info(@"
+Exit codes that normally result from running this command.
+
+Normal:
+ - 0: operation was successful, no issues detected
+ - -1 or 1: an error has occurred
+
+If you find other exit codes that we have not yet documented, please
+ file a ticket so we can document it at
+ https://github.com/chocolatey/choco/issues/new/choose.
+
+");
+
+ "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches");
+ }
+
+ public virtual void noop(ChocolateyConfiguration configuration)
+ {
+ switch (configuration.TemplateCommand.Command)
+ {
+ case TemplateCommandType.list:
+ _templateService.list_noop(configuration);
+ break;
+ case TemplateCommandType.info:
+ _templateService.list_noop(configuration);
+ break;
+ }
+ }
+
+ public virtual void run(ChocolateyConfiguration configuration)
+ {
+ switch (configuration.TemplateCommand.Command)
+ {
+ case TemplateCommandType.list:
+ _templateService.list(configuration);
+ break;
+ case TemplateCommandType.info:
+ configuration.Verbose = true;
+ _templateService.list(configuration);
+ break;
+ }
+ }
+
+ public virtual bool may_require_admin_access()
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs
index c4ec782330..f597e7b1fe 100644
--- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs
+++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs
@@ -51,6 +51,7 @@ public ChocolateyConfiguration()
OutdatedCommand = new OutdatedCommandConfiguration();
Proxy = new ProxyConfiguration();
ExportCommand = new ExportCommandConfiguration();
+ TemplateCommand = new TemplateCommandConfiguration();
#if DEBUG
AllowUnofficialBuild = true;
#endif
@@ -345,6 +346,14 @@ private void append_output(StringBuilder propertyValues, string append)
/// On .NET 4.0, get error CS0200 when private set - see http://stackoverflow.com/a/23809226/18475
///
public ProxyConfiguration Proxy { get; set; }
+
+ ///
+ /// Configuration related specifically to Template command
+ ///
+ ///
+ /// On .NET 4.0, get error CS0200 when private set - see http://stackoverflow.com/a/23809226/18475
+ ///
+ public TemplateCommandConfiguration TemplateCommand { get; set; }
}
[Serializable]
@@ -557,4 +566,11 @@ public sealed class ExportCommandConfiguration
public string OutputFilePath { get; set; }
}
+
+ [Serializable]
+ public sealed class TemplateCommandConfiguration
+ {
+ public TemplateCommandType Command { get; set; }
+ public string Name { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/chocolatey/infrastructure.app/domain/TemplateCommandType.cs b/src/chocolatey/infrastructure.app/domain/TemplateCommandType.cs
new file mode 100644
index 0000000000..8f4cb5bcc1
--- /dev/null
+++ b/src/chocolatey/infrastructure.app/domain/TemplateCommandType.cs
@@ -0,0 +1,25 @@
+// 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.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace chocolatey.infrastructure.app.domain
+{
+ public enum TemplateCommandType
+ {
+ unknown,
+ list,
+ info
+ }
+}
diff --git a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs
index a849a379ee..8e94690ee9 100644
--- a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs
+++ b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs
@@ -97,7 +97,8 @@ public void RegisterComponents(Container container)
new ChocolateyUnpackSelfCommand(container.GetInstance()),
new ChocolateyVersionCommand(container.GetInstance()),
new ChocolateyUpdateCommand(container.GetInstance()),
- new ChocolateyExportCommand(container.GetInstance(), container.GetInstance())
+ new ChocolateyExportCommand(container.GetInstance(), container.GetInstance()),
+ new ChocolateyTemplateCommand(container.GetInstance())
};
return list.AsReadOnly();
}, Lifestyle.Singleton);
diff --git a/src/chocolatey/infrastructure.app/services/ITemplateService.cs b/src/chocolatey/infrastructure.app/services/ITemplateService.cs
index abfe00dfa0..ec757dd50d 100644
--- a/src/chocolatey/infrastructure.app/services/ITemplateService.cs
+++ b/src/chocolatey/infrastructure.app/services/ITemplateService.cs
@@ -22,5 +22,7 @@ public interface ITemplateService
{
void generate_noop(ChocolateyConfiguration configuration);
void generate(ChocolateyConfiguration configuration);
+ void list_noop(ChocolateyConfiguration configuration);
+ void list(ChocolateyConfiguration configuration);
}
}
diff --git a/src/chocolatey/infrastructure.app/services/TemplateService.cs b/src/chocolatey/infrastructure.app/services/TemplateService.cs
index 7a68b491fc..12e986ff2e 100644
--- a/src/chocolatey/infrastructure.app/services/TemplateService.cs
+++ b/src/chocolatey/infrastructure.app/services/TemplateService.cs
@@ -19,18 +19,23 @@ namespace chocolatey.infrastructure.app.services
using System;
using System.Collections.Generic;
using System.IO;
+ using System.Linq;
using System.Reflection;
using System.Text;
using configuration;
- using filesystem;
using logging;
using templates;
using tokens;
+ using NuGet;
+ using nuget;
+ using IFileSystem = filesystem.IFileSystem;
public class TemplateService : ITemplateService
{
private readonly UTF8Encoding utf8WithoutBOM = new UTF8Encoding(false);
private readonly IFileSystem _fileSystem;
+ private readonly ILogger _nugetLogger;
+
private readonly IList _templateBinaryExtensions = new List {
".exe", ".msi", ".msu", ".msp", ".mst",
".7z", ".zip", ".rar", ".gz", ".iso", ".tar", ".sfx",
@@ -38,6 +43,9 @@ public class TemplateService : ITemplateService
".cer", ".crt", ".der", ".p7b", ".pfx", ".p12", ".pem"
};
+ private readonly string _builtInTemplateOverrideName = "default";
+ private readonly string _builtInTemplateName = "built-in";
+
public TemplateService(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
@@ -186,5 +194,162 @@ public void generate_file_from_template(ChocolateyConfiguration configuration, T
_fileSystem.create_directory_if_not_exists(_fileSystem.get_directory_name(fileLocation));
_fileSystem.write_file(fileLocation, template, encoding);
}
+
+ public void list_noop(ChocolateyConfiguration configuration)
+ {
+ if (string.IsNullOrWhiteSpace(configuration.TemplateCommand.Name))
+ {
+ this.Log().Info(() => "Would have listed templates in {0}\\templates".format_with(ApplicationParameters.InstallLocation));
+ }
+ else
+ {
+ this.Log().Info(() => "Would have listed information about {0}".format_with(configuration.TemplateCommand.Name));
+ }
+ }
+
+ public void list(ChocolateyConfiguration configuration)
+ {
+
+ var packageManager = NugetCommon.GetPackageManager(configuration, _nugetLogger,
+ new PackageDownloader(),
+ installSuccessAction: null,
+ uninstallSuccessAction: null,
+ addUninstallHandler: false);
+
+ var templateDirList = _fileSystem.get_directories(ApplicationParameters.TemplatesLocation).ToList();
+ var isBuiltInTemplateOverriden = templateDirList.Contains(_fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, _builtInTemplateOverrideName));
+ var isBuiltInOrDefaultTemplateDefault = string.IsNullOrWhiteSpace(configuration.DefaultTemplateName) || !templateDirList.Contains(_fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, configuration.DefaultTemplateName));
+
+ if (string.IsNullOrWhiteSpace(configuration.TemplateCommand.Name))
+ {
+
+ if (templateDirList.Any())
+ {
+ foreach (var templateDir in templateDirList)
+ {
+ configuration.TemplateCommand.Name = _fileSystem.get_file_name(templateDir);
+ list_custom_template_info(configuration, packageManager);
+ }
+
+ this.Log().Info(configuration.RegularOutput ? "{0} Custom templates found at {1}{2}".format_with(templateDirList.Count(), ApplicationParameters.TemplatesLocation, Environment.NewLine) : string.Empty);
+ }
+ else
+ {
+ this.Log().Info(configuration.RegularOutput ? "No custom templates installed in {0}{2}".format_with(ApplicationParameters.TemplatesLocation, Environment.NewLine) : string.Empty);
+ }
+
+ list_built_in_template_info(configuration, isBuiltInTemplateOverriden, isBuiltInOrDefaultTemplateDefault);
+ }
+ else
+ {
+ if (templateDirList.Contains(_fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, configuration.TemplateCommand.Name)))
+ {
+ list_custom_template_info(configuration, packageManager);
+ if (configuration.TemplateCommand.Name == _builtInTemplateName || configuration.TemplateCommand.Name == _builtInTemplateOverrideName)
+ {
+ list_built_in_template_info(configuration, isBuiltInTemplateOverriden, isBuiltInOrDefaultTemplateDefault);
+ }
+ }
+ else
+ {
+ if (configuration.TemplateCommand.Name.ToLowerInvariant() == _builtInTemplateName || configuration.TemplateCommand.Name.ToLowerInvariant() == _builtInTemplateOverrideName)
+ {
+ // We know that the template is not overriden since the template directory was checked
+ list_built_in_template_info(configuration, isBuiltInTemplateOverriden, isBuiltInOrDefaultTemplateDefault);
+ }
+ else
+ {
+ throw new ApplicationException("Unable to find requested template '{0}'".format_with(configuration.TemplateCommand.Name));
+ }
+ }
+ }
+ }
+
+ protected void list_custom_template_info(ChocolateyConfiguration configuration, IPackageManager packageManager)
+ {
+
+ var pkg = packageManager.LocalRepository.FindPackage("{0}.template".format_with(configuration.TemplateCommand.Name));
+ var pkgVersion = (pkg == null) ? "0.0.0" : pkg.Version.to_string();
+ var pkgTitle = (pkg == null) ? "{0} (Unmanaged)".format_with(configuration.TemplateCommand.Name) : pkg.Title;
+ var pkgSummary = (pkg == null) ?
+ string.Empty : (pkg.Summary != null && !string.IsNullOrWhiteSpace(pkg.Summary.to_string()) ? "{0}".format_with(pkg.Summary.escape_curly_braces().to_string()) : string.Empty);
+ var pkgDescription = (pkg == null) ? string.Empty : pkg.Description.escape_curly_braces().Replace("\n ", "\n").Replace("\n", "\n ");
+ var pkgFiles = " {0}".format_with(string.Join("{0} "
+ .format_with(Environment.NewLine), _fileSystem.get_files(_fileSystem
+ .combine_paths(ApplicationParameters.TemplatesLocation, configuration.TemplateCommand.Name), "*", SearchOption.AllDirectories)));
+
+ var isOverridingBuiltIn = configuration.TemplateCommand.Name == _builtInTemplateOverrideName;
+ var isDefault = string.IsNullOrWhiteSpace(configuration.DefaultTemplateName) ? isOverridingBuiltIn : (configuration.DefaultTemplateName == configuration.TemplateCommand.Name);
+
+ if (configuration.RegularOutput)
+ {
+ if (configuration.Verbose)
+ {
+ // TODO list parameters, do later (save to file?)
+ this.Log().Info(@"Template name: {0}
+Version: {1}
+Default template: {2}
+{3}Title: {4}
+{5}{6}
+List of files:
+{7}
+List of Parameters:
+ Will be implemented at a later time
+".format_with(configuration.TemplateCommand.Name,
+ pkgVersion,
+ isDefault,
+ isOverridingBuiltIn ? "This template is overriding the built in template{0}".format_with(Environment.NewLine) : string.Empty,
+ pkgTitle,
+ string.IsNullOrEmpty(pkgSummary) ? "Template not installed as a package" : "Summary: {0}".format_with(pkgSummary),
+ string.IsNullOrEmpty(pkgDescription) ? string.Empty : "{0}Description:{0} {1}".format_with(Environment.NewLine, pkgDescription),
+ pkgFiles));
+ }
+ else
+ {
+ this.Log().Info("{0} {1} {2}".format_with((isDefault ? '*' : ' '), configuration.TemplateCommand.Name, pkgVersion));
+ }
+ }
+ else
+ {
+ this.Log().Info("{0}|{1}".format_with(configuration.TemplateCommand.Name, pkgVersion));
+ }
+ }
+
+ protected void list_built_in_template_info(ChocolateyConfiguration configuration, bool isOverridden, bool isDefault)
+ {
+ if (configuration.RegularOutput)
+ {
+ if (isOverridden)
+ {
+ this.Log().Info("Built-in template overriden by 'default' template.{0}".format_with(Environment.NewLine));
+ }
+ else
+ {
+ if (isDefault)
+ {
+ this.Log().Info("Built-in template is default.{0}".format_with(Environment.NewLine));
+ }
+ else
+ {
+ this.Log().Info("Built-in template is not default, it can be specified if the --built-in parameter is used{0}".format_with(Environment.NewLine));
+ }
+
+ }
+
+ if (configuration.Verbose)
+ {
+ this.Log().Info("Help about the built-in template can be found with 'choco new --help'{0}".format_with(Environment.NewLine));
+ }
+ }
+ else
+ {
+ //If reduced output, only print out the built in template if it is not overriden
+ if (!isOverridden)
+ {
+ this.Log().Info("built-in|0.0.0");
+ }
+ }
+
+ }
}
}