Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New argument added for customizing end-of-line characters in output files #6

Merged
merged 9 commits into from
Mar 30, 2024
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Tool is customisable, take a look at list of all arguments that can be passed. E
| -y | --to-yaml | :heavy_check_mark: | Indicates whether configuration wrapped in YAML Azure DevOps variables file | `false` |
| -f | --file-path-template | :heavy_check_mark: | File name template for output. Template may contain a placeholder for environment name. Example: `configuration.{0}.json` | `./configuration.json` |
| -e | --environments | :heavy_check_mark: | A list of environment names. Separate configuration file will be created per each environment. Required when file name template contains placeholder | |
| -l | -eol | :heavy_check_mark: | Customize end-of-line characters, possible values: `Cr`, `CrLf` or `Lf`, when skipped, operating system default end-of-line characters will be used | |

### Configuration providers
If you'd like to include all the settings collected by different configuration provider, add them all by `--providers` option. More information about [configuration providers](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"antyrama.tools.scribe.cli": {
"version": "0.0.3-rc",
"version": "0.0.5",
"commands": [
"app-settings-to-file"
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
Expand All @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Antyrama.Tools.Scribe.Core" Version="0.0.3-rc" />
<PackageReference Include="Antyrama.Tools.Scribe.Core" Version="0.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion examples/src/ExampleWebAppSimple/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"antyrama.tools.scribe.cli": {
"version": "0.0.3-rc",
"version": "0.0.5",
"commands": [
"app-settings-to-file"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Antyrama.Tools.Scribe.Core" Version="0.0.3-rc" />
<PackageReference Include="Antyrama.Tools.Scribe.Core" Version="0.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public void Generate()
.ToDictionary(s => s.Key, s => s.Value);

var repository = _options.WrapInYaml
? (ConfigurationRepository)new YamlConfigurationRepository(_options.YamlVariableName)
: new JsonConfigurationRepository();
? (ConfigurationRepository)new YamlConfigurationRepository(_options.YamlVariableName, _options)
: new JsonConfigurationRepository(_options);

foreach (var filename in GetConfigurationFiles(_options))
{
Expand All @@ -48,7 +48,7 @@ public void Generate()
}
}

private IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> Load(IConfigurationRepository repository, string filename)
private static IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> Load(IConfigurationRepository repository, string filename)
{
try
{
Expand All @@ -62,7 +62,7 @@ private IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> Load(IC
}
}

private void Save(IConfigurationRepository repository, string filename, IEnumerable<IReadOnlyDictionary<string, object>> settings)
private static void Save(IConfigurationRepository repository, string filename, IEnumerable<IReadOnlyDictionary<string, object>> settings)
{
using var stream = new FileStream(filename, FileMode.Create, FileAccess.Write);

Expand Down Expand Up @@ -119,6 +119,5 @@ private IEnumerable<string> GetConfigurationFiles(ToolInternalOptions options)
}

throw new InvalidOperationException("File path template must contain '{0}' as environment placeholder when environments specified.");

}
}
2 changes: 1 addition & 1 deletion src/Antyrama.Tools.Scribe.Core/ConfigurationCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public IReadOnlyList<KeyValuePair<string, string>> Collect(string pathSeparator)
return settings;
}

private void Collect(IConfigurationSection section, ICollection<KeyValuePair<string, string>> settings,
private static void Collect(IConfigurationSection section, ICollection<KeyValuePair<string, string>> settings,
string pathSeparator)
{
if (section == null || string.IsNullOrEmpty(section.Key))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,26 @@ internal interface IConfigurationRepository

internal abstract class ConfigurationRepository : IConfigurationRepository
{
protected readonly string Eol;

protected ConfigurationRepository(ToolInternalOptions options)
{
Eol = ResolveEndOfLine(options);
}

public abstract IReadOnlyDictionary<string, object>[] Load(Stream stream);

public abstract void Save(Stream stream, IEnumerable<IReadOnlyDictionary<string, object>> settings);

protected static string Serialize(IEnumerable<IReadOnlyDictionary<string, object>> settings)
protected string Serialize(IEnumerable<IReadOnlyDictionary<string, object>> settings)
{
var serialized = settings.Select(setting => $" {JsonConvert.SerializeObject(setting)}");

var separator = $",{Environment.NewLine}";
var separator = $",{Eol}";
var formatted = string.Join(separator, serialized)
.BeautifyJson();

return $"[{Environment.NewLine}{formatted}{Environment.NewLine}]";
return $"[{Eol}{formatted}{Eol}]";
}

protected static IReadOnlyDictionary<string, object>[] Deserialize(string settings)
Expand All @@ -43,4 +50,20 @@ protected static IReadOnlyDictionary<string, object>[] Deserialize(string settin
return Array.Empty<IReadOnlyDictionary<string, object>>();
}
}

private static string ResolveEndOfLine(ToolInternalOptions options)
{
return options.Eol switch
{
EndOfLine.Cr => Cr,
EndOfLine.CrLf => CrLf,
EndOfLine.Lf => Lf,
null => Environment.NewLine,
_ => throw new ArgumentOutOfRangeException(nameof(options))
};
}

private const string Cr = "\r";
private const string CrLf = "\r\n";
private const string Lf = "\n";
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ namespace Antyrama.Tools.Scribe.Core.Repository;

internal class JsonConfigurationRepository : ConfigurationRepository
{
public JsonConfigurationRepository(ToolInternalOptions options) : base(options)
{
}

public override IReadOnlyDictionary<string, object>[] Load(Stream stream)
{
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ internal class YamlConfigurationRepository : ConfigurationRepository
private readonly Serializer _serializer;
private readonly Deserializer _deserializer;

public YamlConfigurationRepository(string variableName)
public YamlConfigurationRepository(string variableName, ToolInternalOptions options)
: base(options)
{
_serializer = new SerializerBuilder()
.WithAttributeOverride<Variables>(variables => variables.AppConfig,
Expand Down Expand Up @@ -55,8 +56,11 @@ public override void Save(Stream stream, IEnumerable<IReadOnlyDictionary<string,
}
};

var yaml = _serializer.Serialize(root);
yaml = yaml.Replace(Environment.NewLine, Eol);

var writer = new StreamWriter(stream);
_serializer.Serialize(writer, root);
writer.Write(yaml);
writer.Flush();
}
}
15 changes: 15 additions & 0 deletions src/Antyrama.Tools.Scribe.Core/ToolOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public class ToolOptions
[Option('e', "environments", Required = false, Default = new string[0],
HelpText = "A list of environment names. Separate configuration file will be created per each environment. Required when file name template contains placeholder.")]
public IEnumerable<string> EnvironmentsList { get; set; }

[Option('l', "eol", Required = false,
HelpText = "End-of-line delimiter, possible values: Cr, CrLf or Lf, by default operating system end-of-line will be used.")]
public EndOfLine? Eol { get; set; }
}

[Verb("_generate", Hidden = true)]
Expand Down Expand Up @@ -75,4 +79,15 @@ public class ToolInternalOptions
[Option('e', "environments", Required = false, Default = new string[0],
HelpText = "A list of environment names. Separate configuration file will be created per each environment. Required when file name template contains placeholder.")]
public IEnumerable<string> Environments { get; set; }

[Option('l', "eol", Required = false,
HelpText = "End-of-line delimiter, possible values: Cr, CrLf or Lf, by default operating system end-of-line will be used.")]
public EndOfLine? Eol { get; set; }
}

public enum EndOfLine
{
Cr,
CrLf,
Lf
}
37 changes: 37 additions & 0 deletions tests/UnitTests/Repository/JsonConfigurationRepositoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Text;
using Antyrama.Tools.Scribe.Core;
using Antyrama.Tools.Scribe.Core.Repository;
using FluentAssertions;

namespace UnitTests.Repository;

public sealed class JsonConfigurationRepositoryTests
{
[Theory]
[InlineData(EndOfLine.CrLf, "\r\n")]
[InlineData(EndOfLine.Cr, "\r")]
[InlineData(EndOfLine.Lf, "\n")]
public void ShouldWriteAndReadConfigFileWithAllPossibleEndOfLines(EndOfLine? eol, string eolChars)
{
// arrange
var options = new ToolInternalOptions { Eol = eol };
var sut = new JsonConfigurationRepository(options);

using var stream = new MemoryStream();

// act
sut.Save(stream,
new IReadOnlyDictionary<string, object>[]
{
new Dictionary<string, object> { { "key1", "value1" }, { "key2", "value2" } }
});

// assert
stream.Seek(0, SeekOrigin.Begin);

using var reader = new StreamReader(stream, Encoding.UTF8);
var result = reader.ReadToEnd();

result.Should().Contain(eolChars);
}
}
Loading