Skip to content

Commit

Permalink
Supply CodeGenSettings via a JSON file to AutoRest. CodeGenSettings i…
Browse files Browse the repository at this point in the history
…s de-serialized as Dictionary<string, object> so it can contain more complex properties than just strings. (Azure#1147)

It passed the CI check we ran on another node. One CI servers is hanging alot.
  • Loading branch information
jhancock93 authored and fearthecowboy committed Jun 10, 2016
1 parent 89362bb commit 31e5a52
Show file tree
Hide file tree
Showing 13 changed files with 102 additions and 19 deletions.
3 changes: 3 additions & 0 deletions AutoRest/AutoRest.Core.Tests/AutoRest.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
<None Include="Resource\RedisResource.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Resource\SampleSettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Templates\SampleModel.cshtml" />
</ItemGroup>
<ItemGroup>
Expand Down
25 changes: 23 additions & 2 deletions AutoRest/AutoRest.Core.Tests/AutoRestSettingsTests.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Rest.Generator.Logging;
using Newtonsoft.Json.Linq;
using Xunit;

namespace Microsoft.Rest.Generator.Test
Expand All @@ -16,11 +20,11 @@ public void CreateWithoutArgumentsReturnsBlankSettings()
{
var settings = Settings.Create((string[]) null);
Assert.NotNull(settings);
settings = Settings.Create((IDictionary<string, string>) null);
settings = Settings.Create((IDictionary<string, object>) null);
Assert.NotNull(settings);
settings = Settings.Create(new string[0]);
Assert.NotNull(settings);
settings = Settings.Create(new Dictionary<string, string>());
settings = Settings.Create(new Dictionary<string, object>());
Assert.NotNull(settings);
}

Expand All @@ -33,6 +37,23 @@ public void CreateWithMultipleEmptyKeysStoreInCustomDictonary()
Assert.Equal("", settings.CustomSettings["Bar"]);
}

[Fact]
public void LoadCodeGenSettingsFromJsonFile()
{
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
var settingsFile = Path.Combine(dirPath, "Resource\\SampleSettings.json");
var settings = Settings.Create(new[] {"-cgs", settingsFile});
Assert.False((bool) settings.CustomSettings["sampleSwitchFalse"]);
Assert.True((bool) settings.CustomSettings["sampleSwitchTrue"]);
Assert.Equal("Foo", settings.CustomSettings["sampleString"]);
Assert.Equal(typeof (JArray), settings.CustomSettings["filePathArray"].GetType());
Assert.Equal(2, ((JArray) settings.CustomSettings["filePathArray"]).Count);
Assert.Equal(typeof (JArray), settings.CustomSettings["intArray"].GetType());
Assert.Equal(typeof (long), settings.CustomSettings["intFoo"].GetType());
}

[Fact]
public void EmptyCredentialsSettingIsSetToTrueIfPassed()
{
Expand Down
8 changes: 8 additions & 0 deletions AutoRest/AutoRest.Core.Tests/Resource/SampleSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"sampleSwitchFalse": false,
"sampleSwitchTrue": true,
"sampleString": "Foo",
"filePathArray": [ "C:\\Foo.dll", "C:\\Bar.dll" ],
"intArray": [ 1, 2, 3 ],
"intFoo": 5
}
2 changes: 1 addition & 1 deletion AutoRest/AutoRest.Core/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public virtual string HeaderFileExtension
/// Populate settings on self and any child objects
/// </summary>
/// <param name="settings">A dictionary of settings</param>
public virtual void PopulateSettings(IDictionary<string, string> settings)
public virtual void PopulateSettings(IDictionary<string, object> settings)
{
Settings.PopulateSettings(this, settings);
}
Expand Down
9 changes: 9 additions & 0 deletions AutoRest/AutoRest.Core/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions AutoRest/AutoRest.Core/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
<data name="CodeGenerationFailed" xml:space="preserve">
<value>Code generation failed with errors. See inner exceptions for details.</value>
</data>
<data name="CodeGenSettingsFileInvalid" xml:space="preserve">
<value>Could not load CodeGenSettings file '{0}'. Exception: '{1}'.</value>
</data>
<data name="CommentString" xml:space="preserve">
<value>\\\\</value>
</data>
Expand Down
51 changes: 43 additions & 8 deletions AutoRest/AutoRest.Core/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Microsoft.Rest.Generator.Properties;
using Microsoft.Rest.Generator.Utilities;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Microsoft.Rest.Generator
{
Expand Down Expand Up @@ -46,7 +48,7 @@ public Settings()
{
FileSystem = new FileSystem();
OutputDirectory = Path.Combine(Environment.CurrentDirectory, "Generated");
CustomSettings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
CustomSettings = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
Header = string.Format(CultureInfo.InvariantCulture, DefaultCodeGenerationHeader, AutoRest.Version);
CodeGenerator = "CSharp";
Modeler = "Swagger";
Expand All @@ -60,7 +62,7 @@ public Settings()
/// <summary>
/// Custom provider specific settings.
/// </summary>
public IDictionary<string, string> CustomSettings { get; private set; }
public IDictionary<string, object> CustomSettings { get; private set; }

// The CommandLineInfo attribute is reflected to display help.
// Prefer to show required properties before optional.
Expand Down Expand Up @@ -215,6 +217,9 @@ public string Header
[SettingsInfo("Package version of then generated code package. Should be then version wanted for the package in then package manager.")]
public string PackageVersion { get; set; }

[SettingsAlias("cgs")]
[SettingsInfo("The path for a json file containing code generation settings.")]
public string CodeGenSettings { get; set; }
/// <summary>
/// Factory method to generate CodeGenerationSettings from command line arguments.
/// Matches dictionary keys to the settings properties.
Expand All @@ -223,7 +228,7 @@ public string Header
/// <returns>CodeGenerationSettings</returns>
public static Settings Create(string[] arguments)
{
var argsDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var argsDictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
if (arguments != null && arguments.Length > 0)
{
string key = null;
Expand Down Expand Up @@ -257,7 +262,7 @@ public static Settings Create(string[] arguments)
return Create(argsDictionary);
}

private static void AddArgumentToDictionary(string key, string value, Dictionary<string, string> argsDictionary)
private static void AddArgumentToDictionary(string key, string value, IDictionary<string, object> argsDictionary)
{
key = key ?? "Default";
value = value ?? String.Empty;
Expand All @@ -270,7 +275,7 @@ private static void AddArgumentToDictionary(string key, string value, Dictionary
/// </summary>
/// <param name="settings">Dictionary of settings</param>
/// <returns>Settings</returns>
public static Settings Create(IDictionary<string, string> settings)
public static Settings Create(IDictionary<string, object> settings)
{
var autoRestSettings = new Settings();
if (settings == null || settings.Count == 0)
Expand All @@ -281,6 +286,16 @@ public static Settings Create(IDictionary<string, string> settings)
PopulateSettings(autoRestSettings, settings);

autoRestSettings.CustomSettings = settings;
if (!string.IsNullOrEmpty(autoRestSettings.CodeGenSettings))
{
var settingsContent = autoRestSettings.FileSystem.ReadFileAsText(autoRestSettings.CodeGenSettings);
var codeGenSettingsDictionary =
JsonConvert.DeserializeObject<Dictionary<string, object>>(settingsContent);
foreach (var pair in codeGenSettingsDictionary)
{
autoRestSettings.CustomSettings[pair.Key] = pair.Value;
}
}
return autoRestSettings;
}

Expand All @@ -290,7 +305,7 @@ public static Settings Create(IDictionary<string, string> settings)
/// <param name="entityToPopulate">Object to populate from dictionary.</param>
/// <param name="settings">Dictionary of settings.Settings that are populated get removed from the dictionary.</param>
/// <returns>Dictionary of settings that were not matched.</returns>
public static void PopulateSettings(object entityToPopulate, IDictionary<string, string> settings)
public static void PopulateSettings(object entityToPopulate, IDictionary<string, object> settings)
{
if (entityToPopulate == null)
{
Expand All @@ -311,13 +326,33 @@ public static void PopulateSettings(object entityToPopulate, IDictionary<string,
{
try
{
if (setting.Value.IsNullOrEmpty() && property.PropertyType == typeof(bool))
if (property.PropertyType == typeof(bool) && (setting.Value == null || setting.Value.ToString().IsNullOrEmpty()))
{
property.SetValue(entityToPopulate, true);
}
else if (property.PropertyType.IsEnum)
{
property.SetValue(entityToPopulate, Enum.Parse(property.PropertyType, setting.Value, true));
property.SetValue(entityToPopulate, Enum.Parse(property.PropertyType, setting.Value.ToString(), true));
}
else if (property.PropertyType.IsArray && setting.Value.GetType() == typeof(JArray))
{
var elementType = property.PropertyType.GetElementType();
if (elementType == typeof(string))
{
var stringArray = ((JArray) setting.Value).Children().
Select(
c => c.ToString())
.ToArray();

property.SetValue(entityToPopulate, stringArray);
}
else if (elementType == typeof (int))
{
var intValues = ((JArray)setting.Value).Children().
Select(c => (int)Convert.ChangeType(c, elementType, CultureInfo.InvariantCulture))
.ToArray();
property.SetValue(entityToPopulate, intValues);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public AzureCSharpCodeNamer(Settings settings)
if (setting.Equals("useDateTimeOffset", StringComparison.OrdinalIgnoreCase))
{
bool toUse;
if (bool.TryParse(settings.CustomSettings[setting], out toUse))
if (bool.TryParse(settings.CustomSettings[setting].ToString(), out toUse))
{
UseDateTimeOffset = toUse;
}
Expand Down
2 changes: 1 addition & 1 deletion AutoRest/Generators/CSharp/CSharp/CSharpCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public override string ImplementationFileExtension
get { return ".cs"; }
}

public override void PopulateSettings(IDictionary<string, string> settings)
public override void PopulateSettings(IDictionary<string, object> settings)
{
base.PopulateSettings(settings);
Settings.PopulateSettings(_namer, settings);
Expand Down
2 changes: 1 addition & 1 deletion AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public RubyCodeGenerator(Settings settings) : base(settings)

if (Settings.CustomSettings.ContainsKey("Name"))
{
this.sdkName = Settings.CustomSettings["Name"];
this.sdkName = Settings.CustomSettings["Name"].ToString();
}

if (sdkName == null)
Expand Down
4 changes: 3 additions & 1 deletion AutoRest/Modelers/Swagger/SwaggerModeler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ private void UpdateSettings()
{
foreach (var key in ServiceDefinition.Info.CodeGenerationSettings.Extensions.Keys)
{
this.Settings.CustomSettings[key] = ServiceDefinition.Info.CodeGenerationSettings.Extensions[key].ToString();
//Don't overwrite settings that come in from the command line
if (!this.Settings.CustomSettings.ContainsKey(key))
this.Settings.CustomSettings[key] = ServiceDefinition.Info.CodeGenerationSettings.Extensions[key];
}
Settings.PopulateSettings(this.Settings, this.Settings.CustomSettings);
}
Expand Down
7 changes: 4 additions & 3 deletions Documentation/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
**-OutputFileName** If set, will cause generated code to be output to a single file. Not supported by all code generators.

**-Verbose** If set, will output verbose diagnostic messages.


**-CodeGenSettings** Optionally specifies a JSON file that contains code generation settings equivalent to the swagger document containing the same content in the [x-ms-code-generation-settings] extension. Aliases: -cgs
##Code Generators
**Ruby** Generic Ruby code generator.

Expand Down Expand Up @@ -68,7 +69,7 @@ AutoRest.exe -Namespace MyNamespace -Input swagger.json
AutoRest.exe -Namespace MyNamespace -Header "Copyright Contoso Ltd" -Input swagger.json
```

- Generate C# client with a credentials property in MyNamespace from swagger.json input:
- Generate C# client with a credentials property in MyNamespace from swagger.json input and with code generation settings specified by settings.json:
```bash
AutoRest.exe -AddCredentials true -Namespace MyNamespace -CodeGenerator CSharp -Modeler Swagger -Input swagger.json
AutoRest.exe -AddCredentials true -Namespace MyNamespace -CodeGenerator CSharp -Modeler Swagger -Input swagger.json -CodeGenSettings settings.json
```
3 changes: 2 additions & 1 deletion Documentation/swagger-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ Field Name | Type | Description
"info": {
"x-ms-code-generation-settings": {
"header": "MIT",
"internalConstructors": true
"internalConstructors": true,
"useDateTimeOffset": true
}
}
```
Expand Down

0 comments on commit 31e5a52

Please sign in to comment.