diff --git a/src/Microsoft.Tye.Core/ConfigModel/ConfigFactory.cs b/src/Microsoft.Tye.Core/ConfigModel/ConfigFactory.cs index e6f5a3f44..31097eb27 100644 --- a/src/Microsoft.Tye.Core/ConfigModel/ConfigFactory.cs +++ b/src/Microsoft.Tye.Core/ConfigModel/ConfigFactory.cs @@ -3,8 +3,13 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Dynamic; using System.IO; +using k8s; +using k8s.Models; using Microsoft.Tye.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Tye.Serialization; namespace Microsoft.Tye.ConfigModel @@ -16,6 +21,9 @@ public static ConfigApplication FromFile(FileInfo file) var extension = file.Extension.ToLowerInvariant(); switch (extension) { + case ".json": + return FromJson(file); + case ".yaml": case ".yml": return FromYaml(file); @@ -88,5 +96,16 @@ private static ConfigApplication FromYaml(FileInfo file) using var parser = new YamlParser(file); return parser.ParseConfigApplication(); } + + private static ConfigApplication FromJson(FileInfo file) + { + var converter = new ExpandoObjectConverter(); + dynamic obj = JsonConvert.DeserializeObject(file.OpenText().ReadToEnd(), converter); + var serializer = new YamlDotNet.Serialization.Serializer(); + string yamlContent = serializer.Serialize(obj); + + using var parser = new YamlParser(yamlContent); + return parser.ParseConfigApplication(); + } } } diff --git a/src/Microsoft.Tye.Core/Serialization/YamlSerializer.cs b/src/Microsoft.Tye.Core/Serialization/YamlSerializer.cs index 4fc55be52..205972862 100644 --- a/src/Microsoft.Tye.Core/Serialization/YamlSerializer.cs +++ b/src/Microsoft.Tye.Core/Serialization/YamlSerializer.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Linq; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -17,5 +18,23 @@ public static ISerializer CreateSerializer() .WithEmissionPhaseObjectGraphVisitor(args => new OmitDefaultAndEmptyArrayObjectGraphVisitor(args.InnerVisitor)) .Build(); } + + public static string ConvertToJson(string yamlContent) + { + var schema = "\"$schema\" : \"https://raw.githubusercontent.com/dotnet/tye/master/src/schema/tye-schema.json\","; + var deserializer = new DeserializerBuilder().Build(); + var yamlObject = deserializer.Deserialize(yamlContent); + + var serializer = new SerializerBuilder() + .JsonCompatible() + .Build(); + + var json = serializer.Serialize(yamlObject); + + if (string.IsNullOrEmpty(json)) + json = json.Insert(json.IndexOf("{") + 1, schema); + + return json; + } } } diff --git a/src/tye/InitHost.cs b/src/tye/InitHost.cs index 435042369..9c27bcf60 100644 --- a/src/tye/InitHost.cs +++ b/src/tye/InitHost.cs @@ -6,21 +6,30 @@ namespace Microsoft.Tye { public static class InitHost { - public static string CreateTyeFile(FileInfo? path, bool force) + public static string CreateTyeFile(FileInfo? path, bool force, bool json = false) { - var (content, outputFilePath) = CreateTyeFileContent(path, force); + var (content, outputFilePath) = CreateTyeFileContent(path, force, json); - File.WriteAllText(outputFilePath, content); + if (json) + { + var jsonContent = YamlSerializer.ConvertToJson(content); + File.WriteAllText(outputFilePath, jsonContent); + } + else + { + File.WriteAllText(outputFilePath, content); + } return outputFilePath; } - public static (string, string) CreateTyeFileContent(FileInfo? path, bool force) + public static (string, string) CreateTyeFileContent(FileInfo? path, bool force, bool json = false) { if (path is FileInfo && path.Exists && !force) { ThrowIfTyeFilePresent(path, "tye.yml"); ThrowIfTyeFilePresent(path, "tye.yaml"); + ThrowIfTyeFilePresent(path, "tye.json"); } var template = @" @@ -50,7 +59,7 @@ public static (string, string) CreateTyeFileContent(FileInfo? path, bool force) // Output in the current directory unless an input file was provided, then // output next to the input file. - var outputFilePath = "tye.yaml"; + var outputFilePath = json ? "tye.json" : "tye.yaml"; if (path is FileInfo && path.Exists) { @@ -77,7 +86,7 @@ public static (string, string) CreateTyeFileContent(FileInfo? path, bool force) } // If the input file is a sln/project then place the config next to it - outputFilePath = Path.Combine(directory.FullName, "tye.yaml"); + outputFilePath = Path.Combine(directory.FullName, outputFilePath); } else { diff --git a/src/tye/Program.InitCommand.cs b/src/tye/Program.InitCommand.cs index aa6f117fa..bf2381c9b 100644 --- a/src/tye/Program.InitCommand.cs +++ b/src/tye/Program.InitCommand.cs @@ -21,15 +21,21 @@ private static Command CreateInitCommand() CommonArguments.Path_Optional, }; + command.AddOption(new Option(new[] { "--json" }) + { + Description = "Create config file in json format i.e. tye.json", + Required = false + }); + command.AddOption(new Option(new[] { "-f", "--force" }) { Description = "Overrides the tye.yaml file if already present for project.", Required = false }); - command.Handler = CommandHandler.Create((console, path, force) => + command.Handler = CommandHandler.Create((console, path, force, json) => { - var outputFilePath = InitHost.CreateTyeFile(path, force); + var outputFilePath = InitHost.CreateTyeFile(path, force, json); console.Out.WriteLine($"Created '{outputFilePath}'."); }); diff --git a/tye.sln b/tye.sln index c52c1d60d..2366f41e5 100644 --- a/tye.sln +++ b/tye.sln @@ -25,9 +25,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Tye.Extensions", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Tye.Extensions.Configuration", "src\Microsoft.Tye.Extensions.Configuration\Microsoft.Tye.Extensions.Configuration.csproj", "{B07394E4-30A7-429A-BC5A-747B54D5A447}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Tye.Proxy", "src\Microsoft.Tye.Proxy\Microsoft.Tye.Proxy.csproj", "{7C9021B7-64BA-4DA9-88DA-5BC12A1C6233}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Tye.Proxy", "src\Microsoft.Tye.Proxy\Microsoft.Tye.Proxy.csproj", "{7C9021B7-64BA-4DA9-88DA-5BC12A1C6233}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Tye.Extensions.Configuration.Tests", "test\Microsoft.Tye.Extensions.Configuration.Tests\Microsoft.Tye.Extensions.Configuration.Tests.csproj", "{FCE7C889-16D1-42E7-A514-EA096E9D41A7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Tye.Extensions.Configuration.Tests", "test\Microsoft.Tye.Extensions.Configuration.Tests\Microsoft.Tye.Extensions.Configuration.Tests.csproj", "{FCE7C889-16D1-42E7-A514-EA096E9D41A7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -111,6 +111,18 @@ Global {D0359C69-6EA9-4B03-9455-90E8E04F1CB0}.Release|x64.Build.0 = Release|Any CPU {D0359C69-6EA9-4B03-9455-90E8E04F1CB0}.Release|x86.ActiveCfg = Release|Any CPU {D0359C69-6EA9-4B03-9455-90E8E04F1CB0}.Release|x86.Build.0 = Release|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x64.ActiveCfg = Debug|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x64.Build.0 = Debug|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x86.ActiveCfg = Debug|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x86.Build.0 = Debug|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|Any CPU.Build.0 = Release|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x64.ActiveCfg = Release|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x64.Build.0 = Release|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x86.ActiveCfg = Release|Any CPU + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x86.Build.0 = Release|Any CPU {AAF0CE0B-E53A-4E10-AA82-BF7200AB2B0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AAF0CE0B-E53A-4E10-AA82-BF7200AB2B0C}.Debug|Any CPU.Build.0 = Debug|Any CPU {AAF0CE0B-E53A-4E10-AA82-BF7200AB2B0C}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -147,18 +159,6 @@ Global {7C9021B7-64BA-4DA9-88DA-5BC12A1C6233}.Release|x64.Build.0 = Release|Any CPU {7C9021B7-64BA-4DA9-88DA-5BC12A1C6233}.Release|x86.ActiveCfg = Release|Any CPU {7C9021B7-64BA-4DA9-88DA-5BC12A1C6233}.Release|x86.Build.0 = Release|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x64.ActiveCfg = Debug|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x64.Build.0 = Debug|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x86.ActiveCfg = Debug|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Debug|x86.Build.0 = Debug|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|Any CPU.Build.0 = Release|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x64.ActiveCfg = Release|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x64.Build.0 = Release|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x86.ActiveCfg = Release|Any CPU - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A}.Release|x86.Build.0 = Release|Any CPU {FCE7C889-16D1-42E7-A514-EA096E9D41A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FCE7C889-16D1-42E7-A514-EA096E9D41A7}.Debug|Any CPU.Build.0 = Debug|Any CPU {FCE7C889-16D1-42E7-A514-EA096E9D41A7}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -182,10 +182,10 @@ Global {CEBFC149-8162-4A0A-9AD4-40498B9172CD} = {8C662D59-A3CB-466F-8E85-A8E6BA5E7601} {34719884-1338-4965-BA2A-F98DB03733C2} = {8C662D59-A3CB-466F-8E85-A8E6BA5E7601} {D0359C69-6EA9-4B03-9455-90E8E04F1CB0} = {8C662D59-A3CB-466F-8E85-A8E6BA5E7601} + {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A} = {F19B02EB-A372-417A-B2C2-EA0D5A3C76D5} {AAF0CE0B-E53A-4E10-AA82-BF7200AB2B0C} = {8C662D59-A3CB-466F-8E85-A8E6BA5E7601} {B07394E4-30A7-429A-BC5A-747B54D5A447} = {8C662D59-A3CB-466F-8E85-A8E6BA5E7601} {7C9021B7-64BA-4DA9-88DA-5BC12A1C6233} = {8C662D59-A3CB-466F-8E85-A8E6BA5E7601} - {2233F4A8-10F9-40A6-BFD3-8D0C37F8359A} = {F19B02EB-A372-417A-B2C2-EA0D5A3C76D5} {FCE7C889-16D1-42E7-A514-EA096E9D41A7} = {F19B02EB-A372-417A-B2C2-EA0D5A3C76D5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution