diff --git a/src/Hocon.Extensions.Configuration.Tests/IncludeTest.cs b/src/Hocon.Extensions.Configuration.Tests/IncludeTest.cs new file mode 100644 index 0000000..7e11a89 --- /dev/null +++ b/src/Hocon.Extensions.Configuration.Tests/IncludeTest.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Xunit; + +namespace Hocon.Extensions.Configuration.Tests +{ + public class IncludeTest + { + [Fact] + public void ProcessIncludes() + { + var hocon = @"{ + servers { include file(""servers.hocon"") } + }"; + + var hoconConfigSource = new HoconConfigurationSource + { + FileProvider = TestStreamHelpers.StringToFileProvider(hocon), + IncludeCallback = (type, value) => Task.FromResult(@"{ + server1 = 10.0.0.1 + server2 = 10.0.0.2 +}") + }; + + var configurationBuilder = new ConfigurationBuilder(); + configurationBuilder.Add(hoconConfigSource); + var config = configurationBuilder.Build(); + + Assert.Equal("10.0.0.1", config["servers:server1"]); + Assert.Equal("10.0.0.2", config["servers:server2"]); + } + } +} diff --git a/src/Hocon.Extensions.Configuration/HoconConfigurationExtensions.cs b/src/Hocon.Extensions.Configuration/HoconConfigurationExtensions.cs index 654b516..6c6288b 100644 --- a/src/Hocon.Extensions.Configuration/HoconConfigurationExtensions.cs +++ b/src/Hocon.Extensions.Configuration/HoconConfigurationExtensions.cs @@ -72,9 +72,10 @@ public static IConfigurationBuilder AddHoconFile(this IConfigurationBuilder buil /// /// Whether the file is optional. /// Whether the configuration should be reloaded if the file changes. + /// Include callback. /// The . public static IConfigurationBuilder AddHoconFile(this IConfigurationBuilder builder, IFileProvider provider, - string path, bool optional, bool reloadOnChange) + string path, bool optional, bool reloadOnChange, HoconIncludeCallbackAsync includeCallback = null) { if (builder == null) throw new ArgumentNullException(nameof(builder)); if (string.IsNullOrEmpty(path)) throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path)); @@ -85,6 +86,7 @@ public static IConfigurationBuilder AddHoconFile(this IConfigurationBuilder buil s.Path = path; s.Optional = optional; s.ReloadOnChange = reloadOnChange; + s.IncludeCallback = includeCallback; s.ResolveFileProvider(); }); } diff --git a/src/Hocon.Extensions.Configuration/HoconConfigurationFileParser.cs b/src/Hocon.Extensions.Configuration/HoconConfigurationFileParser.cs index c0bef12..a13d8b2 100644 --- a/src/Hocon.Extensions.Configuration/HoconConfigurationFileParser.cs +++ b/src/Hocon.Extensions.Configuration/HoconConfigurationFileParser.cs @@ -19,8 +19,16 @@ internal class HoconConfigurationFileParser private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); + private readonly HoconIncludeCallbackAsync _includeCallback; + private string _currentPath; + + public HoconConfigurationFileParser(HoconIncludeCallbackAsync includeCallback) + { + _includeCallback = includeCallback; + } + public IDictionary Parse(Stream input) { _data.Clear(); @@ -28,7 +36,7 @@ public IDictionary Parse(Stream input) using (var textStream = new StreamReader(input)) { var content = textStream.ReadToEnd(); - var hoconConfig = HoconParser.Parse(content); + var hoconConfig = HoconParser.Parse(content, _includeCallback ?? HoconConfigurationSource.DefaultIncludeCallback); VisitHoconObject(hoconConfig.Value.GetObject()); } diff --git a/src/Hocon.Extensions.Configuration/HoconConfigurationProvider.cs b/src/Hocon.Extensions.Configuration/HoconConfigurationProvider.cs index da073a0..64f7076 100644 --- a/src/Hocon.Extensions.Configuration/HoconConfigurationProvider.cs +++ b/src/Hocon.Extensions.Configuration/HoconConfigurationProvider.cs @@ -17,12 +17,15 @@ namespace Hocon.Extensions.Configuration /// public class HoconConfigurationProvider : FileConfigurationProvider { + private readonly HoconConfigurationSource _source; + /// /// Initializes a new instance with the specified source. /// /// The source settings. public HoconConfigurationProvider(HoconConfigurationSource source) : base(source) { + _source = source ?? throw new ArgumentNullException(nameof(source)); } /// @@ -31,7 +34,7 @@ public HoconConfigurationProvider(HoconConfigurationSource source) : base(source /// The stream to read. public override void Load(Stream stream) { - var parser = new HoconConfigurationFileParser(); + var parser = new HoconConfigurationFileParser(_source.IncludeCallback); try { Data = parser.Parse(stream); diff --git a/src/Hocon.Extensions.Configuration/HoconConfigurationSource.cs b/src/Hocon.Extensions.Configuration/HoconConfigurationSource.cs index c76a3fa..dbfa9cd 100644 --- a/src/Hocon.Extensions.Configuration/HoconConfigurationSource.cs +++ b/src/Hocon.Extensions.Configuration/HoconConfigurationSource.cs @@ -13,6 +13,16 @@ namespace Hocon.Extensions.Configuration /// public class HoconConfigurationSource : FileConfigurationSource { + /// + /// Default include callback. + /// + public static HoconIncludeCallbackAsync DefaultIncludeCallback { get; set; } = null; + + /// + /// Include callback for this source. + /// + public HoconIncludeCallbackAsync IncludeCallback { get; set; } = null; + /// /// Builds the for this source. ///