Skip to content

Commit 565c083

Browse files
TheCakeIsNaOHgep13
authored andcommitted
(chocolatey#2500) List parameters in templates
This adds the ability for the template command to list the parameters in templates. If the template is installed via a package, the parameters get cached in a file called .parameters in the template's directory. This file is ignored by calls to choco new, as it is excluded from being copied. There another method added to TokenReplacer to get the parameters via regex. This keeps the regex in the TokenReplacer class.
1 parent 974a3bc commit 565c083

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

src/chocolatey.tests/infrastructure.app/services/TemplateServiceSpecs.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace chocolatey.tests.infrastructure.app.services
2626
using chocolatey.infrastructure.app.services;
2727
using chocolatey.infrastructure.app.templates;
2828
using chocolatey.infrastructure.filesystem;
29+
using chocolatey.infrastructure.services;
2930
using Moq;
3031
using NUnit.Framework;
3132
using Should;
@@ -36,12 +37,14 @@ public abstract class TemplateServiceSpecsBase : TinySpec
3637
{
3738
protected TemplateService service;
3839
protected Mock<IFileSystem> fileSystem = new Mock<IFileSystem>();
40+
protected Mock<IXmlService> xmlService = new Mock<IXmlService>();
3941

4042
public override void Context()
4143
{
4244
fileSystem.ResetCalls();
45+
xmlService.ResetCalls();
4346

44-
service = new TemplateService(fileSystem.Object);
47+
service = new TemplateService(fileSystem.Object, xmlService.Object);
4548
}
4649
}
4750

src/chocolatey/infrastructure.app/services/TemplateService.cs

+61-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace chocolatey.infrastructure.app.services
2323
using System.Reflection;
2424
using System.Text;
2525
using configuration;
26+
using infrastructure.services;
2627
using logging;
2728
using templates;
2829
using tokens;
@@ -35,6 +36,7 @@ public class TemplateService : ITemplateService
3536
private readonly UTF8Encoding utf8WithoutBOM = new UTF8Encoding(false);
3637
private readonly IFileSystem _fileSystem;
3738
private readonly ILogger _nugetLogger;
39+
private readonly IXmlService _xmlService;
3840

3941
private readonly IList<string> _templateBinaryExtensions = new List<string> {
4042
".exe", ".msi", ".msu", ".msp", ".mst",
@@ -45,10 +47,12 @@ public class TemplateService : ITemplateService
4547

4648
private readonly string _builtInTemplateOverrideName = "default";
4749
private readonly string _builtInTemplateName = "built-in";
50+
private readonly string _templateParameterCacheFilename = ".parameters";
4851

49-
public TemplateService(IFileSystem fileSystem)
52+
public TemplateService(IFileSystem fileSystem, IXmlService xmlService)
5053
{
5154
_fileSystem = fileSystem;
55+
_xmlService = xmlService;
5256
}
5357

5458
public void generate_noop(ChocolateyConfiguration configuration)
@@ -148,6 +152,7 @@ public void generate(ChocolateyConfiguration configuration)
148152
configuration.NewCommand.TemplateName = string.IsNullOrWhiteSpace(configuration.NewCommand.TemplateName) ? "default" : configuration.NewCommand.TemplateName;
149153

150154
var templatePath = _fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, configuration.NewCommand.TemplateName);
155+
var templateParameterCachePath = _fileSystem.combine_paths(templatePath, _templateParameterCacheFilename);
151156
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));
152157

153158
this.Log().Info(configuration.QuietOutput ? logger : ChocolateyLoggers.Important, "Generating package from custom template at '{0}'.".format_with(templatePath));
@@ -174,6 +179,10 @@ public void generate(ChocolateyConfiguration configuration)
174179
this.Log().Debug(" Treating template file ('{0}') as binary instead of replacing templated values.".format_with(_fileSystem.get_file_name(file)));
175180
_fileSystem.copy_file(file, packageFileLocation, overwriteExisting:true);
176181
}
182+
else if (templateParameterCachePath.is_equal_to(file))
183+
{
184+
this.Log().Debug("{0} is the parameter cache file, ignoring".format_with(file));
185+
}
177186
else
178187
{
179188
generate_file_from_template(configuration, tokens, _fileSystem.read_file(file), packageFileLocation, Encoding.UTF8);
@@ -280,6 +289,7 @@ protected void list_custom_template_info(ChocolateyConfiguration configuration,
280289
.combine_paths(ApplicationParameters.TemplatesLocation, configuration.TemplateCommand.Name), "*", SearchOption.AllDirectories)));
281290
var isOverridingBuiltIn = configuration.TemplateCommand.Name == _builtInTemplateOverrideName;
282291
var isDefault = string.IsNullOrWhiteSpace(configuration.DefaultTemplateName) ? isOverridingBuiltIn : (configuration.DefaultTemplateName == configuration.TemplateCommand.Name);
292+
var templateParams = " {0}".format_with(string.Join("{0} ".format_with(Environment.NewLine), get_template_parameters(configuration, templateInstalledViaPackage)));
283293

284294
if (configuration.RegularOutput)
285295
{
@@ -292,14 +302,17 @@ protected void list_custom_template_info(ChocolateyConfiguration configuration,
292302
{5}{6}
293303
List of files:
294304
{7}
305+
List of Parameters:
306+
{8}
295307
".format_with(configuration.TemplateCommand.Name,
296308
pkgVersion,
297309
isDefault,
298310
isOverridingBuiltIn ? "This template is overriding the built in template{0}".format_with(Environment.NewLine) : string.Empty,
299311
pkgTitle,
300312
string.IsNullOrEmpty(pkgSummary) ? "Template not installed as a package" : "Summary: {0}".format_with(pkgSummary),
301313
string.IsNullOrEmpty(pkgDescription) ? string.Empty : "{0}Description:{0} {1}".format_with(Environment.NewLine, pkgDescription),
302-
pkgFiles));
314+
pkgFiles,
315+
templateParams));
303316
}
304317
else
305318
{
@@ -345,5 +358,51 @@ protected void list_built_in_template_info(ChocolateyConfiguration configuration
345358
}
346359
}
347360
}
361+
362+
protected IEnumerable<string> get_template_parameters(ChocolateyConfiguration configuration, bool templateInstalledViaPackage)
363+
{
364+
// If the template was installed via package, the cache file gets removed on upgrade, so the cache file would be up to date if it exists
365+
if (templateInstalledViaPackage)
366+
{
367+
var templateDirectory = _fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, configuration.TemplateCommand.Name);
368+
var cacheFilePath = _fileSystem.combine_paths(templateDirectory, _templateParameterCacheFilename);
369+
370+
if (!_fileSystem.file_exists(cacheFilePath))
371+
{
372+
_xmlService.serialize(get_template_parameters_from_files(configuration).ToList(), cacheFilePath);
373+
}
374+
375+
return _xmlService.deserialize<List<string>>(cacheFilePath);
376+
}
377+
// If the template is not installed via a package, always read the parameters directly as the template may have been updated manually
378+
379+
return get_template_parameters_from_files(configuration).ToList();
380+
}
381+
382+
protected HashSet<string> get_template_parameters_from_files(ChocolateyConfiguration configuration)
383+
{
384+
var filesList = _fileSystem.get_files(_fileSystem.combine_paths(ApplicationParameters.TemplatesLocation, configuration.TemplateCommand.Name), "*", SearchOption.AllDirectories);
385+
var parametersList = new HashSet<string>();
386+
387+
foreach (var filePath in filesList)
388+
{
389+
if (_templateBinaryExtensions.Contains(_fileSystem.get_file_extension(filePath)))
390+
{
391+
this.Log().Debug("{0} is a binary file, not reading parameters".format_with(filePath));
392+
continue;
393+
}
394+
395+
if (_fileSystem.get_file_name(filePath) == _templateParameterCacheFilename)
396+
{
397+
this.Log().Debug("{0} is the parameter cache file, not reading parameters".format_with(filePath));
398+
continue;
399+
}
400+
401+
var fileContents = _fileSystem.read_file(filePath);
402+
parametersList.UnionWith(TokenReplacer.get_tokens(fileContents, "[[", "]]"));
403+
}
404+
405+
return parametersList;
406+
}
348407
}
349408
}

src/chocolatey/infrastructure/tokens/TokenReplacer.cs

+11
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,16 @@ private static IDictionary<string, string> create_dictionary_from_configuration<
6161

6262
return propertyDictionary;
6363
}
64+
65+
public static IEnumerable<string> get_tokens(string textWithTokens, string tokenPrefix = "[[", string tokenSuffix = "]]")
66+
{
67+
var regexMatches = Regex.Matches(textWithTokens, "{0}(?<key>\\w+){1}"
68+
.format_with(Regex.Escape(tokenPrefix), Regex.Escape(tokenSuffix))
69+
);
70+
foreach (Match regexMatch in regexMatches)
71+
{
72+
yield return regexMatch.Groups["key"].to_string();
73+
}
74+
}
6475
}
6576
}

0 commit comments

Comments
 (0)