using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; namespace Google.ProtocolBuffers.ProtoGen { /// /// Preprocesses any input files with an extension of '.proto' by running protoc.exe. If arguments /// are supplied with '--' prefix they are provided to protoc.exe, otherwise they are assumed to /// be used for ProtoGen.exe which is run on the resulting output proto buffer. If the option /// --descriptor_set_out= is specified the proto buffer file is kept, otherwise it will be removed /// after code generation. /// public class ProgramPreprocess { private static int Main(string[] args) { try { return Environment.ExitCode = Run(args); } catch (Exception ex) { Console.Error.WriteLine(ex); return Environment.ExitCode = 2; } } public static int Run(params string[] args) { bool deleteFile = false; string tempFile = null; int result; bool doHelp = args.Length == 0; try { List protocArgs = new List(); List protoGenArgs = new List(); foreach (string arg in args) { doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "/?"); doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "/help"); doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "-?"); doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "-help"); if (arg.StartsWith("--descriptor_set_out=")) { tempFile = arg.Substring("--descriptor_set_out=".Length); protoGenArgs.Add(tempFile); } } if (doHelp) { Console.WriteLine(); Console.WriteLine("PROTOC.exe: Use any of the following options that begin with '--':"); Console.WriteLine(); try { RunProtoc("--help"); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("PROTOGEN.exe: The following options are used to specify defaults for code generation."); Console.WriteLine(); Program.Main(new string[0]); return 0; } foreach (string arg in args) { if (arg.StartsWith("--")) { protocArgs.Add(arg); } else if (File.Exists(arg) && StringComparer.OrdinalIgnoreCase.Equals(".proto", Path.GetExtension(arg))) { if (tempFile == null) { deleteFile = true; tempFile = Path.GetTempFileName(); protocArgs.Add(String.Format("--descriptor_set_out={0}", tempFile)); protoGenArgs.Add(tempFile); } protocArgs.Add(arg); } else { protoGenArgs.Add(arg); } } if (tempFile != null) { result = RunProtoc(protocArgs.ToArray()); if (result != 0) { return result; } } result = Program.Main(protoGenArgs.ToArray()); } finally { if (deleteFile && tempFile != null && File.Exists(tempFile)) { File.Delete(tempFile); } } return result; } private static int RunProtoc(params string[] args) { const string protoc = "protoc.exe"; string exePath = protoc; // Why oh why is this not in System.IO.Path or Environment...? List searchPath = new List(); searchPath.Add(Environment.CurrentDirectory); searchPath.Add(AppDomain.CurrentDomain.BaseDirectory); searchPath.AddRange((Environment.GetEnvironmentVariable("PATH") ?? String.Empty).Split(Path.PathSeparator)); foreach (string path in searchPath) { if (File.Exists(exePath = Path.Combine(path, protoc))) { break; } } if (!File.Exists(exePath)) { throw new FileNotFoundException("Unable to locate " + protoc + " make sure it is in the PATH, cwd, or exe dir."); } for (int i = 0; i < args.Length; i++) { if (args[i].IndexOf(' ') > 0 && args[i][0] != '"') { args[i] = '"' + args[i] + '"'; } } ProcessStartInfo psi = new ProcessStartInfo(exePath); psi.Arguments = String.Join(" ", args); psi.RedirectStandardError = true; psi.RedirectStandardInput = false; psi.RedirectStandardOutput = true; psi.ErrorDialog = false; psi.CreateNoWindow = true; psi.UseShellExecute = false; psi.WorkingDirectory = Environment.CurrentDirectory; Process process = Process.Start(psi); if (process == null) { return 1; } process.WaitForExit(); string tmp = process.StandardOutput.ReadToEnd(); if (tmp.Trim().Length > 0) { Console.Out.WriteLine(tmp); } tmp = process.StandardError.ReadToEnd(); if (tmp.Trim().Length > 0) { Console.Error.WriteLine(tmp); } return process.ExitCode; } } }