diff options
Diffstat (limited to 'src/ProtoGen/GeneratorOptions.cs')
-rw-r--r-- | src/ProtoGen/GeneratorOptions.cs | 613 |
1 files changed, 329 insertions, 284 deletions
diff --git a/src/ProtoGen/GeneratorOptions.cs b/src/ProtoGen/GeneratorOptions.cs index 05317724..ec500d82 100644 --- a/src/ProtoGen/GeneratorOptions.cs +++ b/src/ProtoGen/GeneratorOptions.cs @@ -1,285 +1,330 @@ -#region Copyright notice and license - -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://github.com/jskeet/dotnet-protobufs/ -// Original C++/Java/Python code: -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using Google.ProtocolBuffers.DescriptorProtos; -using Google.ProtocolBuffers.Descriptors; - -namespace Google.ProtocolBuffers.ProtoGen { - /// <summary> - /// All the configuration required for the generator - where to generate - /// output files, the location of input files etc. While this isn't immutable - /// in practice, the contents shouldn't be changed after being passed to - /// the generator. - /// </summary> - public sealed class GeneratorOptions { - - private static Dictionary<string, string> LineBreaks = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) { - { "Windows", "\r\n" }, - { "Unix", "\n" }, - { "Default", Environment.NewLine } - }; - - public IList<string> InputFiles { get; set; } - - public GeneratorOptions() { - LineBreak = Environment.NewLine; - } - - /// <summary> - /// Attempts to validate the options, but doesn't throw an exception if they're invalid. - /// Instead, when this method returns false, the output variable will contain a collection - /// of reasons for the validation failure. - /// </summary> - /// <param name="reasons">Variable to receive a list of reasons in case of validation failure.</param> - /// <returns>true if the options are valid; false otherwise</returns> - public bool TryValidate(out IList<string> reasons) { - List<string> tmpReasons = new List<string>(); - - ParseArguments(tmpReasons); - - // Output directory validation - if (string.IsNullOrEmpty(FileOptions.OutputDirectory)) { - tmpReasons.Add("No output directory specified"); - } - else { - if (!Directory.Exists(FileOptions.OutputDirectory)) { - tmpReasons.Add("Specified output directory (" + FileOptions.OutputDirectory + " doesn't exist."); - } - } - - // Input file validation (just in terms of presence) - if (InputFiles == null || InputFiles.Count == 0) { - tmpReasons.Add("No input files specified"); - } - else { - foreach (string input in InputFiles) { - FileInfo fi = new FileInfo(input); - if (!fi.Exists) { - tmpReasons.Add("Input file " + input + " doesn't exist."); - } - } - } - - if (tmpReasons.Count != 0) { - reasons = tmpReasons; - return false; - } - - reasons = null; - return true; - } - - /// <summary> - /// Validates that all the options have been set and are valid, - /// throwing an exception if they haven't. - /// </summary> - /// <exception cref="InvalidOptionsException">The options are invalid.</exception> - public void Validate() { - IList<string> reasons; - if (!TryValidate(out reasons)) { - throw new InvalidOptionsException(reasons); - } - } - - // Raw arguments, used to provide defaults for proto file options - public IList<string> Arguments { get; set; } - - [Obsolete("Please use GeneratorOptions.FileOptions.OutputDirectory instead")] - public string OutputDirectory { - get { return FileOptions.OutputDirectory; } - set { - CSharpFileOptions.Builder bld = FileOptions.ToBuilder(); - bld.OutputDirectory = value; - FileOptions = bld.Build(); - } - } - - private static readonly Regex ArgMatch = new Regex(@"^[-/](?<name>[\w_]+?)[:=](?<value>.*)$"); - private CSharpFileOptions fileOptions; - - public CSharpFileOptions FileOptions { - get { return fileOptions ?? (fileOptions = CSharpFileOptions.DefaultInstance); } - set { fileOptions = value; } - } - - public string LineBreak { get; set; } - - private void ParseArguments(IList<string> tmpReasons) { - bool doHelp = Arguments.Count == 0; - - InputFiles = new List<string>(); - CSharpFileOptions.Builder builder = FileOptions.ToBuilder(); - Dictionary<string, FieldDescriptor> fields = - new Dictionary<string, FieldDescriptor>(StringComparer.OrdinalIgnoreCase); - foreach (FieldDescriptor fld in builder.DescriptorForType.Fields) { - fields.Add(fld.Name, fld); - } - - foreach (string argument in Arguments) { - if (StringComparer.OrdinalIgnoreCase.Equals("-help", argument) || - StringComparer.OrdinalIgnoreCase.Equals("/help", argument) || - StringComparer.OrdinalIgnoreCase.Equals("-?", argument) || - StringComparer.OrdinalIgnoreCase.Equals("/?", argument)) { - doHelp = true; - break; - } - - Match m = ArgMatch.Match(argument); - if (m.Success) { - FieldDescriptor fld; - string name = m.Groups["name"].Value; - string value = m.Groups["value"].Value; - - if (fields.TryGetValue(name, out fld)) { - object obj; - if (TryCoerceType(value, fld, out obj, tmpReasons)) { - builder[fld] = obj; - } - } else if (name == "line_break") { - string tmp; - if (LineBreaks.TryGetValue(value, out tmp)) { - LineBreak = tmp; - } else { - tmpReasons.Add("Invalid value for 'line_break': " + value + "."); - } - } else if (!File.Exists(argument)) { - doHelp = true; - tmpReasons.Add("Unknown argument '" + name + "'."); - } else { - InputFiles.Add(argument); - } - } - else { - InputFiles.Add(argument); - } - } - - if (doHelp || InputFiles.Count == 0) { - tmpReasons.Add("Arguments:"); - foreach (KeyValuePair<string, FieldDescriptor> field in fields) { - tmpReasons.Add(String.Format("-{0}=[{1}]", field.Key, field.Value.FieldType)); - } - tmpReasons.Add("-line_break=[" + string.Join("|", new List<string>(LineBreaks.Keys).ToArray()) + "]"); - tmpReasons.Add("followed by one or more file paths."); - } - else { - FileOptions = builder.Build(); - } - } - - private static bool TryCoerceType(string text, FieldDescriptor field, out object value, IList<string> tmpReasons) { - value = null; - - switch (field.FieldType) { - case FieldType.Int32: - case FieldType.SInt32: - case FieldType.SFixed32: - value = Int32.Parse(text); - break; - - case FieldType.Int64: - case FieldType.SInt64: - case FieldType.SFixed64: - value = Int64.Parse(text); - break; - - case FieldType.UInt32: - case FieldType.Fixed32: - value = UInt32.Parse(text); - break; - - case FieldType.UInt64: - case FieldType.Fixed64: - value = UInt64.Parse(text); - break; - - case FieldType.Float: - value = float.Parse(text); - break; - - case FieldType.Double: - value = Double.Parse(text); - break; - - case FieldType.Bool: - value = Boolean.Parse(text); - break; - - case FieldType.String: - value = text; - break; - - case FieldType.Enum: { - EnumDescriptor enumType = field.EnumType; - - int number; - if (int.TryParse(text, out number)) { - value = enumType.FindValueByNumber(number); - if (value == null) { - tmpReasons.Add( - "Enum type \"" + enumType.FullName + - "\" has no value with number " + number + "."); - return false; - } - } - else { - value = enumType.FindValueByName(text); - if (value == null) { - tmpReasons.Add( - "Enum type \"" + enumType.FullName + - "\" has no value named \"" + text + "\"."); - return false; - } - } - - break; - } - - case FieldType.Bytes: - case FieldType.Message: - case FieldType.Group: - tmpReasons.Add("Unhandled field type " + field.FieldType.ToString() + "."); - return false; - } - - return true; - } - } +#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// All the configuration required for the generator - where to generate
+ /// output files, the location of input files etc. While this isn't immutable
+ /// in practice, the contents shouldn't be changed after being passed to
+ /// the generator.
+ /// </summary>
+ public sealed class GeneratorOptions
+ {
+ private static Dictionary<string, string> LineBreaks =
+ new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"Windows", "\r\n"},
+ {"Unix", "\n"},
+ {"Default", Environment.NewLine}
+ };
+
+ public IList<string> InputFiles { get; set; }
+
+ public GeneratorOptions()
+ {
+ LineBreak = Environment.NewLine;
+ }
+
+ /// <summary>
+ /// Attempts to validate the options, but doesn't throw an exception if they're invalid.
+ /// Instead, when this method returns false, the output variable will contain a collection
+ /// of reasons for the validation failure.
+ /// </summary>
+ /// <param name="reasons">Variable to receive a list of reasons in case of validation failure.</param>
+ /// <returns>true if the options are valid; false otherwise</returns>
+ public bool TryValidate(out IList<string> reasons)
+ {
+ List<string> tmpReasons = new List<string>();
+
+ ParseArguments(tmpReasons);
+
+ // Output directory validation
+ if (string.IsNullOrEmpty(FileOptions.OutputDirectory))
+ {
+ tmpReasons.Add("No output directory specified");
+ }
+ else
+ {
+ if (!Directory.Exists(FileOptions.OutputDirectory))
+ {
+ tmpReasons.Add("Specified output directory (" + FileOptions.OutputDirectory + " doesn't exist.");
+ }
+ }
+
+ // Input file validation (just in terms of presence)
+ if (InputFiles == null || InputFiles.Count == 0)
+ {
+ tmpReasons.Add("No input files specified");
+ }
+ else
+ {
+ foreach (string input in InputFiles)
+ {
+ FileInfo fi = new FileInfo(input);
+ if (!fi.Exists)
+ {
+ tmpReasons.Add("Input file " + input + " doesn't exist.");
+ }
+ }
+ }
+
+ if (tmpReasons.Count != 0)
+ {
+ reasons = tmpReasons;
+ return false;
+ }
+
+ reasons = null;
+ return true;
+ }
+
+ /// <summary>
+ /// Validates that all the options have been set and are valid,
+ /// throwing an exception if they haven't.
+ /// </summary>
+ /// <exception cref="InvalidOptionsException">The options are invalid.</exception>
+ public void Validate()
+ {
+ IList<string> reasons;
+ if (!TryValidate(out reasons))
+ {
+ throw new InvalidOptionsException(reasons);
+ }
+ }
+
+ // Raw arguments, used to provide defaults for proto file options
+ public IList<string> Arguments { get; set; }
+
+ [Obsolete("Please use GeneratorOptions.FileOptions.OutputDirectory instead")]
+ public string OutputDirectory
+ {
+ get { return FileOptions.OutputDirectory; }
+ set
+ {
+ CSharpFileOptions.Builder bld = FileOptions.ToBuilder();
+ bld.OutputDirectory = value;
+ FileOptions = bld.Build();
+ }
+ }
+
+ private static readonly Regex ArgMatch = new Regex(@"^[-/](?<name>[\w_]+?)[:=](?<value>.*)$");
+ private CSharpFileOptions fileOptions;
+
+ public CSharpFileOptions FileOptions
+ {
+ get { return fileOptions ?? (fileOptions = CSharpFileOptions.DefaultInstance); }
+ set { fileOptions = value; }
+ }
+
+ public string LineBreak { get; set; }
+
+ private void ParseArguments(IList<string> tmpReasons)
+ {
+ bool doHelp = Arguments.Count == 0;
+
+ InputFiles = new List<string>();
+ CSharpFileOptions.Builder builder = FileOptions.ToBuilder();
+ Dictionary<string, FieldDescriptor> fields =
+ new Dictionary<string, FieldDescriptor>(StringComparer.OrdinalIgnoreCase);
+ foreach (FieldDescriptor fld in builder.DescriptorForType.Fields)
+ {
+ fields.Add(fld.Name, fld);
+ }
+
+ foreach (string argument in Arguments)
+ {
+ if (StringComparer.OrdinalIgnoreCase.Equals("-help", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("/help", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("-?", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("/?", argument))
+ {
+ doHelp = true;
+ break;
+ }
+
+ Match m = ArgMatch.Match(argument);
+ if (m.Success)
+ {
+ FieldDescriptor fld;
+ string name = m.Groups["name"].Value;
+ string value = m.Groups["value"].Value;
+
+ if (fields.TryGetValue(name, out fld))
+ {
+ object obj;
+ if (TryCoerceType(value, fld, out obj, tmpReasons))
+ {
+ builder[fld] = obj;
+ }
+ }
+ else if (name == "line_break")
+ {
+ string tmp;
+ if (LineBreaks.TryGetValue(value, out tmp))
+ {
+ LineBreak = tmp;
+ }
+ else
+ {
+ tmpReasons.Add("Invalid value for 'line_break': " + value + ".");
+ }
+ }
+ else if (!File.Exists(argument))
+ {
+ doHelp = true;
+ tmpReasons.Add("Unknown argument '" + name + "'.");
+ }
+ else
+ {
+ InputFiles.Add(argument);
+ }
+ }
+ else
+ {
+ InputFiles.Add(argument);
+ }
+ }
+
+ if (doHelp || InputFiles.Count == 0)
+ {
+ tmpReasons.Add("Arguments:");
+ foreach (KeyValuePair<string, FieldDescriptor> field in fields)
+ {
+ tmpReasons.Add(String.Format("-{0}=[{1}]", field.Key, field.Value.FieldType));
+ }
+ tmpReasons.Add("-line_break=[" + string.Join("|", new List<string>(LineBreaks.Keys).ToArray()) + "]");
+ tmpReasons.Add("followed by one or more file paths.");
+ }
+ else
+ {
+ FileOptions = builder.Build();
+ }
+ }
+
+ private static bool TryCoerceType(string text, FieldDescriptor field, out object value, IList<string> tmpReasons)
+ {
+ value = null;
+
+ switch (field.FieldType)
+ {
+ case FieldType.Int32:
+ case FieldType.SInt32:
+ case FieldType.SFixed32:
+ value = Int32.Parse(text);
+ break;
+
+ case FieldType.Int64:
+ case FieldType.SInt64:
+ case FieldType.SFixed64:
+ value = Int64.Parse(text);
+ break;
+
+ case FieldType.UInt32:
+ case FieldType.Fixed32:
+ value = UInt32.Parse(text);
+ break;
+
+ case FieldType.UInt64:
+ case FieldType.Fixed64:
+ value = UInt64.Parse(text);
+ break;
+
+ case FieldType.Float:
+ value = float.Parse(text);
+ break;
+
+ case FieldType.Double:
+ value = Double.Parse(text);
+ break;
+
+ case FieldType.Bool:
+ value = Boolean.Parse(text);
+ break;
+
+ case FieldType.String:
+ value = text;
+ break;
+
+ case FieldType.Enum:
+ {
+ EnumDescriptor enumType = field.EnumType;
+
+ int number;
+ if (int.TryParse(text, out number))
+ {
+ value = enumType.FindValueByNumber(number);
+ if (value == null)
+ {
+ tmpReasons.Add(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value with number " + number + ".");
+ return false;
+ }
+ }
+ else
+ {
+ value = enumType.FindValueByName(text);
+ if (value == null)
+ {
+ tmpReasons.Add(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value named \"" + text + "\".");
+ return false;
+ }
+ }
+
+ break;
+ }
+
+ case FieldType.Bytes:
+ case FieldType.Message:
+ case FieldType.Group:
+ tmpReasons.Add("Unhandled field type " + field.FieldType.ToString() + ".");
+ return false;
+ }
+
+ return true;
+ }
+ }
}
\ No newline at end of file |