private CSharpFileOptions BuildOrFakeCSharpOptions() { // TODO(jonskeet): Check if we could use FileDescriptorProto.Descriptor.Name - interesting bootstrap issues if (proto.Name == "google/protobuf/descriptor.proto") { return(new CSharpFileOptions.Builder { Namespace = "Google.ProtocolBuffers.DescriptorProtos", UmbrellaClassname = "DescriptorProtoFile", NestClasses = false, MultipleFiles = false, PublicClasses = true }.Build()); } if (proto.Name == "google/protobuf/csharp_options.proto") { return(new CSharpFileOptions.Builder { Namespace = "Google.ProtocolBuffers.DescriptorProtos", UmbrellaClassname = "CSharpOptions", NestClasses = false, MultipleFiles = false, PublicClasses = true }.Build()); } CSharpFileOptions.Builder builder = CSharpFileOptions.CreateBuilder(); if (proto.Options.HasExtension(DescriptorProtos.CSharpOptions.CSharpFileOptions)) { builder.MergeFrom(proto.Options.GetExtension(DescriptorProtos.CSharpOptions.CSharpFileOptions)); } if (!builder.HasNamespace) { builder.Namespace = Package; } if (!builder.HasMultipleFiles) { builder.MultipleFiles = false; } if (!builder.HasNestClasses) { builder.NestClasses = false; } if (!builder.HasPublicClasses) { builder.PublicClasses = true; } if (!builder.HasUmbrellaClassname) { int lastSlash = Name.LastIndexOf('/'); string baseName = Name.Substring(lastSlash + 1); builder.UmbrellaClassname = NameHelpers.UnderscoresToPascalCase(NameHelpers.StripProto(baseName)); } return(builder.Build()); }
/// <summary> /// Resolves any dependencies and converts FileDescriptorProtos into FileDescriptors. /// The list returned is in the same order as the protos are listed in the descriptor set. /// Note: this method is internal rather than private to allow testing. /// </summary> /// <exception cref="DependencyResolutionException">Not all dependencies could be resolved.</exception> public static IList <FileDescriptor> ConvertDescriptors(CSharpFileOptions options, params FileDescriptorSet[] descriptorProtos) { // Simple strategy: Keep going through the list of protos to convert, only doing ones where // we've already converted all the dependencies, until we get to a stalemate List <FileDescriptorProto> fileList = new List <FileDescriptorProto>(); foreach (FileDescriptorSet set in descriptorProtos) { fileList.AddRange(set.FileList); } FileDescriptor[] converted = new FileDescriptor[fileList.Count]; Dictionary <string, FileDescriptor> convertedMap = new Dictionary <string, FileDescriptor>(); int totalConverted = 0; bool madeProgress = true; while (madeProgress && totalConverted < converted.Length) { madeProgress = false; for (int i = 0; i < converted.Length; i++) { if (converted[i] != null) { // Already done this one continue; } FileDescriptorProto candidate = fileList[i]; FileDescriptor[] dependencies = new FileDescriptor[candidate.DependencyList.Count]; CSharpFileOptions.Builder builder = options.ToBuilder(); if (candidate.Options.HasExtension(CSharpOptions.CSharpFileOptions)) { builder.MergeFrom( candidate.Options.GetExtension(CSharpOptions.CSharpFileOptions)); } CSharpFileOptions localOptions = builder.Build(); bool foundAllDependencies = true; for (int j = 0; j < dependencies.Length; j++) { if (!convertedMap.TryGetValue(candidate.DependencyList[j], out dependencies[j])) { // We can auto-magically resolve these since we already have their description // This way if the file is only referencing options it does not need to be built with the // --include_imports definition. if (localOptions.IgnoreGoogleProtobuf && (candidate.DependencyList[j] == "google/protobuf/csharp_options.proto")) { dependencies[j] = CSharpOptions.Descriptor; continue; } if (localOptions.IgnoreGoogleProtobuf && (candidate.DependencyList[j] == "google/protobuf/descriptor.proto")) { dependencies[j] = DescriptorProtoFile.Descriptor; continue; } foundAllDependencies = false; break; } } if (!foundAllDependencies) { continue; } madeProgress = true; totalConverted++; converted[i] = FileDescriptor.BuildFrom(candidate, dependencies); convertedMap[candidate.Name] = converted[i]; } } if (!madeProgress) { StringBuilder remaining = new StringBuilder(); for (int i = 0; i < converted.Length; i++) { if (converted[i] == null) { if (remaining.Length != 0) { remaining.Append(", "); } FileDescriptorProto failure = fileList[i]; remaining.Append(failure.Name); remaining.Append(":"); foreach (string dependency in failure.DependencyList) { if (!convertedMap.ContainsKey(dependency)) { remaining.Append(" "); remaining.Append(dependency); } } remaining.Append(";"); } } throw new DependencyResolutionException("Unable to resolve all dependencies: " + remaining); } return(Lists.AsReadOnly(converted)); }
private CSharpFileOptions BuildOrFakeWithDefaultOptions(CSharpFileOptions defaultOptions) { // Fix for being able to relocate these files to any directory structure if (proto.Package == "google.protobuf") { string filename = Path.GetFileName(proto.Name); // TODO(jonskeet): Check if we could use FileDescriptorProto.Descriptor.Name - interesting bootstrap issues) if (filename == "descriptor.proto") { return(new CSharpFileOptions.Builder { Namespace = "Google.ProtocolBuffers.DescriptorProtos", UmbrellaClassname = "DescriptorProtoFile", NestClasses = false, MultipleFiles = false, PublicClasses = true, OutputDirectory = defaultOptions.OutputDirectory, IgnoreGoogleProtobuf = defaultOptions.IgnoreGoogleProtobuf }.Build()); } if (filename == "csharp_options.proto") { return(new CSharpFileOptions.Builder { Namespace = "Google.ProtocolBuffers.DescriptorProtos", UmbrellaClassname = "CSharpOptions", NestClasses = false, MultipleFiles = false, PublicClasses = true, OutputDirectory = defaultOptions.OutputDirectory, IgnoreGoogleProtobuf = defaultOptions.IgnoreGoogleProtobuf }.Build()); } } CSharpFileOptions.Builder builder = defaultOptions.ToBuilder(); if (proto.Options.HasExtension(DescriptorProtos.CSharpOptions.CSharpFileOptions)) { builder.MergeFrom(proto.Options.GetExtension(DescriptorProtos.CSharpOptions.CSharpFileOptions)); } if (!builder.HasNamespace) { builder.Namespace = Package; } if (!builder.HasUmbrellaClassname) { int lastSlash = Name.LastIndexOf('/'); string baseName = Name.Substring(lastSlash + 1); builder.UmbrellaClassname = NameHelpers.UnderscoresToPascalCase(NameHelpers.StripProto(baseName)); } // Auto-fix for name collision by placing umbrella class into a new namespace. This // still won't fix the collisions with nesting enabled; however, you have to turn that on explicitly anyway. if (!builder.NestClasses && !builder.HasUmbrellaNamespace) { bool collision = false; foreach (IDescriptor d in MessageTypes) { collision |= d.Name == builder.UmbrellaClassname; } foreach (IDescriptor d in Services) { collision |= d.Name == builder.UmbrellaClassname; } foreach (IDescriptor d in EnumTypes) { collision |= d.Name == builder.UmbrellaClassname; } if (collision) { builder.UmbrellaNamespace = "Proto"; } } return(builder.Build()); }
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(); } }