Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceOverhaul/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/2.4.1/ProtobufCS/src/ProtoGen/GeneratorOptions.cs @ 13957

Last change on this file since 13957 was 8295, checked in by abeham, 12 years ago

#1897:

  • Removed protocol buffers 0.9.1
  • Added protocol buffers 2.4.1
  • Updated proto processing command
File size: 12.2 KB
Line 
1#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc.  All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13//     * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15//     * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19//     * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
38using System.Collections.Generic;
39using System.IO;
40using System.Text.RegularExpressions;
41using Google.ProtocolBuffers.DescriptorProtos;
42using Google.ProtocolBuffers.Descriptors;
43
44namespace Google.ProtocolBuffers.ProtoGen
45{
46    /// <summary>
47    /// All the configuration required for the generator - where to generate
48    /// output files, the location of input files etc. While this isn't immutable
49    /// in practice, the contents shouldn't be changed after being passed to
50    /// the generator.
51    /// </summary>
52    public sealed class GeneratorOptions
53    {
54        private static Dictionary<string, string> LineBreaks =
55            new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
56                {
57                    {"Windows", "\r\n"},
58                    {"Unix", "\n"},
59                    {"Default", Environment.NewLine}
60                };
61
62        public IList<string> InputFiles { get; set; }
63
64        public GeneratorOptions()
65        {
66            LineBreak = Environment.NewLine;
67        }
68
69        /// <summary>
70        /// Attempts to validate the options, but doesn't throw an exception if they're invalid.
71        /// Instead, when this method returns false, the output variable will contain a collection
72        /// of reasons for the validation failure.
73        /// </summary>
74        /// <param name="reasons">Variable to receive a list of reasons in case of validation failure.</param>
75        /// <returns>true if the options are valid; false otherwise</returns>
76        public bool TryValidate(out IList<string> reasons)
77        {
78            List<string> tmpReasons = new List<string>();
79
80            ParseArguments(tmpReasons);
81
82            // Output directory validation
83            if (string.IsNullOrEmpty(FileOptions.OutputDirectory))
84            {
85                tmpReasons.Add("No output directory specified");
86            }
87            else
88            {
89                if (!Directory.Exists(FileOptions.OutputDirectory))
90                {
91                    tmpReasons.Add("Specified output directory (" + FileOptions.OutputDirectory + " doesn't exist.");
92                }
93            }
94
95            // Input file validation (just in terms of presence)
96            if (InputFiles == null || InputFiles.Count == 0)
97            {
98                tmpReasons.Add("No input files specified");
99            }
100            else
101            {
102                foreach (string input in InputFiles)
103                {
104                    FileInfo fi = new FileInfo(input);
105                    if (!fi.Exists)
106                    {
107                        tmpReasons.Add("Input file " + input + " doesn't exist.");
108                    }
109                }
110            }
111
112            if (tmpReasons.Count != 0)
113            {
114                reasons = tmpReasons;
115                return false;
116            }
117
118            reasons = null;
119            return true;
120        }
121
122        /// <summary>
123        /// Validates that all the options have been set and are valid,
124        /// throwing an exception if they haven't.
125        /// </summary>
126        /// <exception cref="InvalidOptionsException">The options are invalid.</exception>
127        public void Validate()
128        {
129            IList<string> reasons;
130            if (!TryValidate(out reasons))
131            {
132                throw new InvalidOptionsException(reasons);
133            }
134        }
135
136        // Raw arguments, used to provide defaults for proto file options
137        public IList<string> Arguments { get; set; }
138
139        [Obsolete("Please use GeneratorOptions.FileOptions.OutputDirectory instead")]
140        public string OutputDirectory
141        {
142            get { return FileOptions.OutputDirectory; }
143            set
144            {
145                CSharpFileOptions.Builder bld = FileOptions.ToBuilder();
146                bld.OutputDirectory = value;
147                FileOptions = bld.Build();
148            }
149        }
150
151        private static readonly Regex ArgMatch = new Regex(@"^[-/](?<name>[\w_]+?)[:=](?<value>.*)$");
152        private CSharpFileOptions fileOptions;
153
154        public CSharpFileOptions FileOptions
155        {
156            get { return fileOptions ?? (fileOptions = CSharpFileOptions.DefaultInstance); }
157            set { fileOptions = value; }
158        }
159
160        public string LineBreak { get; set; }
161
162        private void ParseArguments(IList<string> tmpReasons)
163        {
164            bool doHelp = Arguments.Count == 0;
165
166            InputFiles = new List<string>();
167            CSharpFileOptions.Builder builder = FileOptions.ToBuilder();
168            Dictionary<string, FieldDescriptor> fields =
169                new Dictionary<string, FieldDescriptor>(StringComparer.OrdinalIgnoreCase);
170            foreach (FieldDescriptor fld in builder.DescriptorForType.Fields)
171            {
172                fields.Add(fld.Name, fld);
173            }
174
175            foreach (string argument in Arguments)
176            {
177                if (StringComparer.OrdinalIgnoreCase.Equals("-help", argument) ||
178                    StringComparer.OrdinalIgnoreCase.Equals("/help", argument) ||
179                    StringComparer.OrdinalIgnoreCase.Equals("-?", argument) ||
180                    StringComparer.OrdinalIgnoreCase.Equals("/?", argument))
181                {
182                    doHelp = true;
183                    break;
184                }
185
186                Match m = ArgMatch.Match(argument);
187                if (m.Success)
188                {
189                    FieldDescriptor fld;
190                    string name = m.Groups["name"].Value;
191                    string value = m.Groups["value"].Value;
192
193                    if (fields.TryGetValue(name, out fld))
194                    {
195                        object obj;
196                        if (TryCoerceType(value, fld, out obj, tmpReasons))
197                        {
198                            builder[fld] = obj;
199                        }
200                    }
201                    else if (name == "line_break")
202                    {
203                        string tmp;
204                        if (LineBreaks.TryGetValue(value, out tmp))
205                        {
206                            LineBreak = tmp;
207                        }
208                        else
209                        {
210                            tmpReasons.Add("Invalid value for 'line_break': " + value + ".");
211                        }
212                    }
213                    else if (!File.Exists(argument))
214                    {
215                        doHelp = true;
216                        tmpReasons.Add("Unknown argument '" + name + "'.");
217                    }
218                    else
219                    {
220                        InputFiles.Add(argument);
221                    }
222                }
223                else
224                {
225                    InputFiles.Add(argument);
226                }
227            }
228
229            if (doHelp || InputFiles.Count == 0)
230            {
231                tmpReasons.Add("Arguments:");
232                foreach (KeyValuePair<string, FieldDescriptor> field in fields)
233                {
234                    tmpReasons.Add(String.Format("-{0}=[{1}]", field.Key, field.Value.FieldType));
235                }
236                tmpReasons.Add("-line_break=[" + string.Join("|", new List<string>(LineBreaks.Keys).ToArray()) + "]");
237                tmpReasons.Add("followed by one or more file paths.");
238            }
239            else
240            {
241                FileOptions = builder.Build();
242            }
243        }
244
245        private static bool TryCoerceType(string text, FieldDescriptor field, out object value, IList<string> tmpReasons)
246        {
247            value = null;
248
249            switch (field.FieldType)
250            {
251                case FieldType.Int32:
252                case FieldType.SInt32:
253                case FieldType.SFixed32:
254                    value = Int32.Parse(text);
255                    break;
256
257                case FieldType.Int64:
258                case FieldType.SInt64:
259                case FieldType.SFixed64:
260                    value = Int64.Parse(text);
261                    break;
262
263                case FieldType.UInt32:
264                case FieldType.Fixed32:
265                    value = UInt32.Parse(text);
266                    break;
267
268                case FieldType.UInt64:
269                case FieldType.Fixed64:
270                    value = UInt64.Parse(text);
271                    break;
272
273                case FieldType.Float:
274                    value = float.Parse(text);
275                    break;
276
277                case FieldType.Double:
278                    value = Double.Parse(text);
279                    break;
280
281                case FieldType.Bool:
282                    value = Boolean.Parse(text);
283                    break;
284
285                case FieldType.String:
286                    value = text;
287                    break;
288
289                case FieldType.Enum:
290                    {
291                        EnumDescriptor enumType = field.EnumType;
292
293                        int number;
294                        if (int.TryParse(text, out number))
295                        {
296                            value = enumType.FindValueByNumber(number);
297                            if (value == null)
298                            {
299                                tmpReasons.Add(
300                                    "Enum type \"" + enumType.FullName +
301                                    "\" has no value with number " + number + ".");
302                                return false;
303                            }
304                        }
305                        else
306                        {
307                            value = enumType.FindValueByName(text);
308                            if (value == null)
309                            {
310                                tmpReasons.Add(
311                                    "Enum type \"" + enumType.FullName +
312                                    "\" has no value named \"" + text + "\".");
313                                return false;
314                            }
315                        }
316
317                        break;
318                    }
319
320                case FieldType.Bytes:
321                case FieldType.Message:
322                case FieldType.Group:
323                    tmpReasons.Add("Unhandled field type " + field.FieldType.ToString() + ".");
324                    return false;
325            }
326
327            return true;
328        }
329    }
330}
Note: See TracBrowser for help on using the repository browser.