using Capnp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
[assembly: InternalsVisibleTo("CapnpC.CSharp.Generator.Tests")]
namespace CapnpC.CSharp.Generator
{
///
/// Provides methods for controlling both the C# code generator backend and the frontend "capnpc"
///
public static class CapnpCompilation
{
///
/// Returns the basename of the capnp executable
///
public static string CapnpCompilerFilename
{
get => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "capnp.exe" : "capnp";
}
///
/// Generates C# code from given input stream
///
/// Input stream containing the binary code generation request, which the frontend capnpc emits
/// Configuration options for code generator. If null, default options will be used.
/// generation result
/// if is null
public static GenerationResult GenerateFromStream(Stream input, CodeGen.GeneratorOptions options)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
try
{
var segments = Framing.ReadSegments(input);
var dec = DeserializerState.CreateRoot(segments);
var reader = Schema.CodeGeneratorRequest.READER.create(dec);
var model = Model.SchemaModel.Create(reader);
var codeGen = new CodeGen.CodeGenerator(model, options ?? new CodeGen.GeneratorOptions());
return new GenerationResult(codeGen.Generate());
}
catch (Exception exception)
{
return new GenerationResult(exception);
}
}
///
/// Generates C# code from given input stream
///
/// input stream containing the binary code generation request, which the frontend capnpc emits
/// generation result
/// if is null
public static GenerationResult GenerateFromStream(Stream input) => GenerateFromStream(input, null);
///
/// Invokes "capnp.exe -o-" with given additional arguments and redirects the output to the C# generator backend.
///
/// additional command line arguments
/// optional working directory
/// generation result
/// is null
public static GenerationResult InvokeCapnpAndGenerate(IEnumerable arguments, string workingDirectory = null)
{
if (arguments == null)
throw new ArgumentNullException(nameof(arguments));
using (var compiler = new Process())
{
var argList = new List();
argList.Add("compile");
argList.Add($"-o-");
argList.AddRange(arguments);
compiler.StartInfo.FileName = CapnpCompilerFilename;
compiler.StartInfo.Arguments = string.Join(" ", argList);
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.StartInfo.RedirectStandardError = true;
if (!string.IsNullOrWhiteSpace(workingDirectory))
{
compiler.StartInfo.WorkingDirectory = workingDirectory;
}
try
{
compiler.Start();
}
catch (Exception exception)
{
return new GenerationResult(exception)
{
ErrorCategory = CapnpProcessFailure.NotFound
};
}
var result = GenerateFromStream(compiler.StandardOutput.BaseStream);
var messageList = new List();
while (!compiler.StandardError.EndOfStream)
{
messageList.Add(new CapnpMessage(compiler.StandardError.ReadLine()));
}
result.Messages = messageList;
if (!result.IsSuccess)
{
compiler.WaitForExit();
int exitCode = compiler.ExitCode;
if (exitCode == 0)
result.ErrorCategory = CapnpProcessFailure.BadOutput;
else
result.ErrorCategory = CapnpProcessFailure.BadInput;
}
return result;
}
}
}
}