diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateXmlSerializers.cs b/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateXmlSerializers.cs new file mode 100644 index 00000000000000..c66acf6e07764e --- /dev/null +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateXmlSerializers.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System; +using System.Collections.Generic; + +namespace Microsoft.XmlSerializer.Generator +{ + /// + /// MSBuild task to run the Microsoft.XmlSerializer.Generator directly, + /// without spawning a new process. + /// + public class GenerateXmlSerializers : Task + { + /// + /// Path to the target assembly (usually the output DLL). + /// + [Required] + public string AssemblyPath { get; set; } + + /// + /// Optional path to a response file containing additional generator arguments. + /// + public string RspFilePath { get; set; } + + /// + /// Force regeneration of serializers even if they exist. + /// + public bool Force { get; set; } + + /// + /// Run in quiet mode with minimal output. + /// + public bool Quiet { get; set; } + + /// + /// If true, errors during serializer generation will be suppressed. + /// + public bool IgnoreErrors { get; set; } + + /// + /// Executes the XmlSerializer generator. + /// + public override bool Execute() + { + var args = new List(); + + if (!string.IsNullOrEmpty(AssemblyPath)) + args.Add(AssemblyPath); + + if (Force) + args.Add("--force"); + + if (Quiet) + args.Add("--quiet"); + + if (!string.IsNullOrEmpty(RspFilePath)) + args.Add(RspFilePath); + + Sgen sgen = new Sgen(); + Sgen.InfoWriter = new InfoTextWriter(Log); + Sgen.WarningWriter = new WarningTextWriter(Log); + Sgen.ErrorWriter = new ErrorTextWriter(Log); + + int exitCode = sgen.Run(args.ToArray()); + + if (exitCode != 0) + { + Log.LogError("XmlSerializer failed with exit code {0}.", exitCode); + } + + return IgnoreErrors || exitCode == 0; + } + } +} diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/LogWriter.cs b/src/libraries/Microsoft.XmlSerializer.Generator/src/LogWriter.cs new file mode 100644 index 00000000000000..89f1bb12c3bdb5 --- /dev/null +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/LogWriter.cs @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.XmlSerializer.Generator +{ + internal sealed class InfoTextWriter : TextWriter + { + private readonly TaskLoggingHelper _log; + + public InfoTextWriter(TaskLoggingHelper log) + { + _log = log ?? throw new ArgumentNullException(nameof(log)); + } + + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(string? value) + { + if (!string.IsNullOrEmpty(value)) + { + _log.LogMessage(MessageImportance.High, value); + } + } + + public override void WriteLine(string? value) + { + if (!string.IsNullOrEmpty(value)) + { + _log.LogMessage(MessageImportance.High, value); + } + } + } + + internal sealed class WarningTextWriter : TextWriter + { + private readonly TaskLoggingHelper _log; + + public WarningTextWriter(TaskLoggingHelper log) + { + _log = log ?? throw new ArgumentNullException(nameof(log)); + } + + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(string? value) + { + if (!string.IsNullOrEmpty(value)) + { + _log.LogWarning(value); + } + } + + public override void WriteLine(string? value) + { + if (!string.IsNullOrEmpty(value)) + { + _log.LogWarning(value); + } + } + } + + internal sealed class ErrorTextWriter : TextWriter + { + private readonly TaskLoggingHelper _log; + + public ErrorTextWriter(TaskLoggingHelper log) + { + _log = log ?? throw new ArgumentNullException(nameof(log)); + } + + public override Encoding Encoding => Encoding.UTF8; + + public override void Write(string? value) + { + if (!string.IsNullOrEmpty(value)) + { + _log.LogError(value); + } + } + + public override void WriteLine(string? value) + { + if (!string.IsNullOrEmpty(value)) + { + _log.LogError(value); + } + } + } +} diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj b/src/libraries/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj index a05c036040c043..4990a110cdf788 100644 --- a/src/libraries/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -22,22 +22,24 @@ + + - - - + + + + + + + + + diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/Sgen.cs b/src/libraries/Microsoft.XmlSerializer.Generator/src/Sgen.cs index 74f2d111df056d..0daee0c81607af 100644 --- a/src/libraries/Microsoft.XmlSerializer.Generator/src/Sgen.cs +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/Sgen.cs @@ -25,8 +25,11 @@ public static int Main(string[] args) private static string s_references = string.Empty; private static readonly Dictionary s_referencedic = new Dictionary(StringComparer.OrdinalIgnoreCase); + public static TextWriter InfoWriter { get; internal set; } = Console.Out; + public static TextWriter WarningWriter { get; internal set; } = Console.Out; + public static TextWriter ErrorWriter { get; internal set; } = Console.Error; - private int Run(string[] args) + internal int Run(string[] args) { string assembly = null; var types = new List(); @@ -177,7 +180,7 @@ private int Run(string[] args) { foreach (string err in errs) { - Console.Error.WriteLine(FormatMessage(parsableErrors, true, SR.Format(SR.Warning, err))); + ErrorWriter.WriteLine(FormatMessage(parsableErrors, true, SR.Format(SR.Warning, err))); } } @@ -185,7 +188,7 @@ private int Run(string[] args) { if (assembly == null) { - Console.Error.WriteLine(FormatMessage(parsableErrors, false, SR.Format(SR.ErrMissingRequiredArgument, SR.Format(SR.ErrAssembly, "assembly")))); + ErrorWriter.WriteLine(FormatMessage(parsableErrors, false, SR.Format(SR.ErrMissingRequiredArgument, SR.Format(SR.ErrAssembly, "assembly")))); } WriteHelp(); @@ -194,8 +197,8 @@ private int Run(string[] args) if (disableRun) { - Console.WriteLine("This tool is not intended to be used directly."); - Console.WriteLine("Please refer to https://go.microsoft.com/fwlink/?linkid=858594 on how to use it."); + InfoWriter.WriteLine("This tool is not intended to be used directly."); + InfoWriter.WriteLine("Please refer to https://go.microsoft.com/fwlink/?linkid=858594 on how to use it."); return 0; } @@ -254,7 +257,7 @@ private static void GenerateFile(List typeNames, string defaultNamespace Type type = assembly.GetType(typeName); if (type == null) { - Console.Error.WriteLine(FormatMessage(parsableerrors, false, SR.Format(SR.ErrorDetails, SR.Format(SR.ErrLoadType, typeName, assemblyName)))); + ErrorWriter.WriteLine(FormatMessage(parsableerrors, false, SR.Format(SR.ErrorDetails, SR.Format(SR.ErrLoadType, typeName, assemblyName)))); } types[typeIndex++] = type; @@ -275,7 +278,7 @@ private static void GenerateFile(List typeNames, string defaultNamespace { if (verbose) { - Console.WriteLine(SR.Format(SR.ImportInfo, type.Name, i + 1, types.Length)); + InfoWriter.WriteLine(SR.Format(SR.ImportInfo, type.Name, i + 1, types.Length)); } bool isObsolete = false; @@ -300,7 +303,7 @@ private static void GenerateFile(List typeNames, string defaultNamespace { if (verbose) { - Console.Out.WriteLine(FormatMessage(parsableerrors, true, SR.Format(SR.InfoIgnoreType, type.FullName))); + InfoWriter.WriteLine(FormatMessage(parsableerrors, true, SR.Format(SR.InfoIgnoreType, type.FullName))); WriteWarning(e, parsableerrors); } @@ -372,7 +375,7 @@ private static void GenerateFile(List typeNames, string defaultNamespace if (method == null) { - Console.Error.WriteLine(FormatMessage(parsableerrors: false, warning: false, message: SR.GenerateSerializerNotFound)); + ErrorWriter.WriteLine(FormatMessage(parsableerrors: false, warning: false, message: SR.GenerateSerializerNotFound)); } else { @@ -404,22 +407,21 @@ private static void GenerateFile(List typeNames, string defaultNamespace { if (!silent) { - Console.Out.WriteLine(SR.Format(SR.InfoFileName, codePath)); - Console.Out.WriteLine(SR.Format(SR.InfoGeneratedFile, assembly.Location, codePath)); + InfoWriter.WriteLine(SR.Format(SR.InfoFileName, codePath)); + InfoWriter.WriteLine(SR.Format(SR.InfoGeneratedFile, assembly.Location, codePath)); } } else { - Console.Out.WriteLine(FormatMessage(parsableerrors, false, SR.Format(SR.ErrGenerationFailed, assembly.Location))); + InfoWriter.WriteLine(FormatMessage(parsableerrors, false, SR.Format(SR.ErrGenerationFailed, assembly.Location))); } } else { - Console.Out.WriteLine(FormatMessage(parsableerrors, true, SR.Format(SR.InfoNoSerializableTypes, assembly.Location))); + InfoWriter.WriteLine(FormatMessage(parsableerrors, true, SR.Format(SR.InfoNoSerializableTypes, assembly.Location))); } } - private static bool ArgumentMatch(string arg, string formal) { // Full name format, eg: --assembly @@ -459,7 +461,7 @@ private static void ImportType(Type type, string defaultNamespace, List - + +