diff --git a/README.md b/README.md index 56b209d1..74e37a21 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,9 @@ Options: (default is true) --nc, --netCore generate .NET Core specific code that might not work with .NET Framework (default is false) + --ca, --commandArgs generate a comment with the exact command line + arguments that were used to generate the source + code (default is true) ``` For use from code use the [library NuGet package](https://www.nuget.org/packages/XmlSchemaClassGenerator-beta/): @@ -362,4 +365,4 @@ Contrbutions are welcome. Here are some guidelines: - If it's not a trivial fix, please submit an issue first - Try and blend new code with the existing code's style -- Add unit tests +- Add unit tests \ No newline at end of file diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index 416f2ace..15374ebf 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -54,6 +54,7 @@ static void Main(string[] args) var uniqueTypeNamesAcrossNamespaces = false; var createGeneratedCodeAttributeVersion = true; var netCoreSpecificCode = false; + var generateCommandLineArgs = true; var options = new OptionSet { { "h|help", "show this message and exit", v => showHelp = v != null }, @@ -126,6 +127,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { "un|uniqueTypeNames", "generate type names that are unique across namespaces (default is false)", v => uniqueTypeNamesAcrossNamespaces = v != null }, { "gc|generatedCodeAttribute", "add version information to GeneratedCodeAttribute (default is true)", v => createGeneratedCodeAttributeVersion = v != null }, { "nc|netCore", "generate .NET Core specific code that might not work with .NET Framework (default is false)", v => netCoreSpecificCode = v != null }, + { "ca|commandArgs", "generate a comment with the exact command line arguments that were used to generate the source code (default is true)", v => generateCommandLineArgs = v != null }, }; var globsAndUris = options.Parse(args); @@ -200,7 +202,8 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l CompactTypeNames = compactTypeNames, UniqueTypeNamesAcrossNamespaces = uniqueTypeNamesAcrossNamespaces, CreateGeneratedCodeAttributeVersion = createGeneratedCodeAttributeVersion, - NetCoreSpecificCode = netCoreSpecificCode + NetCoreSpecificCode = netCoreSpecificCode, + GenerateCommandLineArgumentsComment = generateCommandLineArgs, }; generator.CommentLanguages.AddRange(commentLanguages); diff --git a/XmlSchemaClassGenerator.Tests/ExtensionsTests.cs b/XmlSchemaClassGenerator.Tests/ExtensionsTests.cs new file mode 100644 index 00000000..64c11d1e --- /dev/null +++ b/XmlSchemaClassGenerator.Tests/ExtensionsTests.cs @@ -0,0 +1,17 @@ +using Xunit; + +namespace XmlSchemaClassGenerator.Tests +{ + public class ExtensionsTests + { + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("MyText", "MyText")] + [InlineData("My Text", "\"My Text\"")] + public void QuoteEmptyOrNull(string input, string expected) + { + Assert.Equal(expected, input.QuoteIfNeeded()); + } + } +} \ No newline at end of file diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 486fddbe..1b66de13 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -56,7 +56,9 @@ private static IEnumerable ConvertXml(string name, IEnumerable x CodeTypeReferenceOptions = generatorPrototype.CodeTypeReferenceOptions, DoNotForceIsNullable = generatorPrototype.DoNotForceIsNullable, CreateGeneratedCodeAttributeVersion = generatorPrototype.CreateGeneratedCodeAttributeVersion, - NetCoreSpecificCode = generatorPrototype.NetCoreSpecificCode + NetCoreSpecificCode = generatorPrototype.NetCoreSpecificCode, + GenerateCommandLineArgumentsComment = generatorPrototype.GenerateCommandLineArgumentsComment, + CommandLineArgumentsProvider = generatorPrototype.CommandLineArgumentsProvider, }; gen.CommentLanguages.Clear(); @@ -1058,7 +1060,7 @@ public void ComplexTypeWithAttributeGroupExtension() // //------------------------------------------------------------------------------ -// This code was generated by Tests. +// This code was generated by Tests namespace Test { @@ -2388,5 +2390,64 @@ void UnknownAttributeHandler(object sender, XmlAttributeEventArgs e) AssertEx.Equal(deserializedObject, deserializedXml); } } + + [Theory] + [InlineData("fake command line arguments", "fake command line arguments")] + [InlineData(null, "N/A")] + public void IncludeCommandLineArguments(string commandLineArguments, string expectedCommandLineArguments) + { + const string xsd = @" + + + + + +"; + + var generator = new Generator + { + GenerateInterfaces = false, + NamespaceProvider = new NamespaceProvider + { + GenerateNamespace = key => "Test" + }, + GenerateCommandLineArgumentsComment = true, + CommandLineArgumentsProvider = new CommandLineArgumentsProvider(commandLineArguments) + }; + + var contents = ConvertXml(nameof(IncludeCommandLineArguments), xsd, generator); + + var csharp = Assert.Single(contents); + + CompareOutput( + $@"//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// This code was generated by Tests version 1.0.0.1 using the following command: +// {expectedCommandLineArguments} +namespace Test +{{ + + + [System.CodeDom.Compiler.GeneratedCodeAttribute(""Tests"", ""1.0.0.1"")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(""elem"", Namespace=""http://local.none"")] + [System.ComponentModel.DesignerCategoryAttribute(""code"")] + [System.Xml.Serialization.XmlRootAttribute(""document"", Namespace=""http://local.none"")] + public partial class Elem + {{ + + [System.Xml.Serialization.XmlAttributeAttribute(""Text"")] + public string Text {{ get; set; }} + }} +}} +", csharp); + } } } diff --git a/XmlSchemaClassGenerator/CommandLineArgumentsProvider.cs b/XmlSchemaClassGenerator/CommandLineArgumentsProvider.cs new file mode 100644 index 00000000..e71d0c4f --- /dev/null +++ b/XmlSchemaClassGenerator/CommandLineArgumentsProvider.cs @@ -0,0 +1,24 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; + +namespace XmlSchemaClassGenerator +{ + public class CommandLineArgumentsProvider + { + public CommandLineArgumentsProvider(string commandLineArguments) + { + CommandLineArguments = commandLineArguments; + } + + public string CommandLineArguments { get; } + + public static CommandLineArgumentsProvider CreateFromEnvironment() + { + var args = Environment.GetCommandLineArgs(); + var commandLineArguments = string.Join(" ", args.Take(1).Select(Path.GetFileNameWithoutExtension).Concat(args.Skip(1)).Select(Extensions.QuoteIfNeeded)); + return new CommandLineArgumentsProvider(commandLineArguments); + } + } +} \ No newline at end of file diff --git a/XmlSchemaClassGenerator/Extensions.cs b/XmlSchemaClassGenerator/Extensions.cs index be10fcfc..b97d30bc 100644 --- a/XmlSchemaClassGenerator/Extensions.cs +++ b/XmlSchemaClassGenerator/Extensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -41,5 +42,20 @@ public static IEnumerable DistinctBy(this IEnumerable x.First()); } + + public static string QuoteIfNeeded(this string text) + { + if (string.IsNullOrEmpty(text)) + { + return text; + } + + if (text.Contains(" ")) + { + return "\"" + text + "\""; + } + + return text; + } } } diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index 8bb4690e..c2dc59f6 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -288,6 +288,18 @@ public bool NetCoreSpecificCode set { _configuration.NetCoreSpecificCode = value; } } + public bool GenerateCommandLineArgumentsComment + { + get { return _configuration.GenerateCommandLineArgumentsComment; } + set { _configuration.GenerateCommandLineArgumentsComment = value; } + } + + public CommandLineArgumentsProvider CommandLineArgumentsProvider + { + get { return _configuration.CommandLineArgumentsProvider; } + set { _configuration.CommandLineArgumentsProvider = value; } + } + static Generator() { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); @@ -329,9 +341,20 @@ public void Generate(XmlSchemaSet set) { if (Version != null) { - var comment = $"This code was generated by {Version.Title}" - + (CreateGeneratedCodeAttributeVersion ? $" version {Version.Version}." : "."); - ns.Comments.Add(new CodeCommentStatement(comment)); + var comment = new StringBuilder($"This code was generated by {Version.Title}"); + if (CreateGeneratedCodeAttributeVersion) + { + comment.Append($" version {Version.Version}"); + } + if (GenerateCommandLineArgumentsComment) + { + comment.Append(" using the following command:"); + } + ns.Comments.Add(new CodeCommentStatement(comment.ToString())); + if (GenerateCommandLineArgumentsComment) + { + ns.Comments.Add(new CodeCommentStatement(CommandLineArgumentsProvider?.CommandLineArguments ?? "N/A")); + } } writer.Write(ns); diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index 80e79d7b..fa71cfd0 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -38,6 +38,7 @@ public GeneratorConfiguration() NamingProvider = new NamingProvider(NamingScheme); Version = VersionProvider.CreateFromAssembly(); EnableUpaCheck = true; + CommandLineArgumentsProvider = CommandLineArgumentsProvider.CreateFromEnvironment(); } /// @@ -304,5 +305,16 @@ public void WriteLog(string message) /// /// public bool NetCoreSpecificCode { get; set; } + + /// + /// Adds a comment with the exact command line arguments that were used to generate the + /// source code using the . Default is false. + /// + public bool GenerateCommandLineArgumentsComment { get; set; } + + /// + /// A provider to obtain the command line arguments of the tool. + /// + public CommandLineArgumentsProvider CommandLineArgumentsProvider { get; set; } } }