Generator.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Google.ProtocolBuffers.DescriptorProtos;
  5. using System.IO;
  6. using Google.ProtocolBuffers.Descriptors;
  7. using Google.ProtocolBuffers.Collections;
  8. namespace Google.ProtocolBuffers.ProtoGen {
  9. /// <summary>
  10. /// Code generator for protocol buffers. Only C# is supported at the moment.
  11. /// </summary>
  12. public sealed class Generator {
  13. readonly GeneratorOptions options;
  14. private Generator(GeneratorOptions options) {
  15. options.Validate();
  16. this.options = options;
  17. }
  18. /// <summary>
  19. /// Returns a generator configured with the specified options.
  20. /// </summary>
  21. public static Generator CreateGenerator(GeneratorOptions options) {
  22. return new Generator(options);
  23. }
  24. public void Generate() {
  25. foreach (string inputFile in options.InputFiles) {
  26. FileDescriptorSet descriptorProtos;
  27. ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
  28. extensionRegistry.Add(CSharpOptions.CSharpUmbrellaClassname);
  29. extensionRegistry.Add(CSharpOptions.CSharpMultipleFiles);
  30. extensionRegistry.Add(CSharpOptions.CSharpNamespace);
  31. extensionRegistry.Add(CSharpOptions.CSharpNestClasses);
  32. extensionRegistry.Add(CSharpOptions.CSharpPublicClasses);
  33. using (Stream inputStream = File.OpenRead(inputFile)) {
  34. descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
  35. }
  36. IList<FileDescriptor> descriptors = ConvertDescriptors(descriptorProtos);
  37. foreach (FileDescriptor descriptor in descriptors) {
  38. Generate(descriptor);
  39. }
  40. }
  41. }
  42. /// <summary>
  43. /// Generates code for a particular file. All dependencies must
  44. /// already have been resolved.
  45. /// </summary>
  46. private void Generate(FileDescriptor descriptor) {
  47. string umbrellaClass = DescriptorUtil.GetUmbrellaClassName(descriptor);
  48. string ns = DescriptorUtil.GetNamespace(descriptor);
  49. using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, umbrellaClass + ".cs"))) {
  50. TextGenerator writer = new TextGenerator(textWriter);
  51. UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor);
  52. ucg.Generate(writer);
  53. /*
  54. GenerateSiblings(umbrellaSource, descriptor, descriptor.MessageTypes);
  55. GenerateSiblings(umbrellaSource, descriptor, descriptor.EnumTypes);
  56. GenerateSiblings(umbrellaSource, descriptor, descriptor.Services);*/
  57. }
  58. }
  59. private static void GenerateSiblings<T>(SourceFileGenerator parentSourceGenerator, FileDescriptor file, IEnumerable<T> siblings)
  60. where T : IDescriptor {
  61. }
  62. /// <summary>
  63. /// Resolves any dependencies and converts FileDescriptorProtos into FileDescriptors.
  64. /// The list returned is in the same order as the protos are listed in the descriptor set.
  65. /// Note: this method is internal rather than private to allow testing.
  66. /// </summary>
  67. /// <exception cref="DependencyResolutionException">Not all dependencies could be resolved.</exception>
  68. internal static IList<FileDescriptor> ConvertDescriptors(FileDescriptorSet descriptorProtos) {
  69. // Simple strategy: Keep going through the list of protos to convert, only doing ones where
  70. // we've already converted all the dependencies, until we get to a stalemate
  71. IList<FileDescriptorProto> fileList = descriptorProtos.FileList;
  72. FileDescriptor[] converted = new FileDescriptor[fileList.Count];
  73. Dictionary<string, FileDescriptor> convertedMap = new Dictionary<string, FileDescriptor>();
  74. int totalConverted = 0;
  75. bool madeProgress = true;
  76. while (madeProgress && totalConverted < converted.Length) {
  77. madeProgress = false;
  78. for (int i = 0; i < converted.Length; i++) {
  79. if (converted[i] != null) {
  80. // Already done this one
  81. continue;
  82. }
  83. FileDescriptorProto candidate = fileList[i];
  84. FileDescriptor[] dependencies = new FileDescriptor[candidate.DependencyList.Count];
  85. bool foundAllDependencies = true;
  86. for (int j = 0; j < dependencies.Length; j++) {
  87. if (!convertedMap.TryGetValue(candidate.DependencyList[j], out dependencies[j])) {
  88. foundAllDependencies = false;
  89. break;
  90. }
  91. }
  92. if (!foundAllDependencies) {
  93. continue;
  94. }
  95. madeProgress = true;
  96. totalConverted++;
  97. converted[i] = FileDescriptor.BuildFrom(candidate, dependencies);
  98. convertedMap[candidate.Name] = converted[i];
  99. }
  100. }
  101. if (!madeProgress) {
  102. StringBuilder remaining = new StringBuilder();
  103. for (int i = 0; i < converted.Length; i++) {
  104. if (converted[i] == null) {
  105. if (remaining.Length != 0) {
  106. remaining.Append(", ");
  107. }
  108. FileDescriptorProto failure = fileList[i];
  109. remaining.Append(failure.Name);
  110. remaining.Append(":");
  111. foreach (string dependency in failure.DependencyList) {
  112. if (!convertedMap.ContainsKey(dependency)) {
  113. remaining.Append(" ");
  114. remaining.Append(dependency);
  115. }
  116. }
  117. remaining.Append(";");
  118. }
  119. }
  120. throw new DependencyResolutionException("Unable to resolve all dependencies: " + remaining);
  121. }
  122. return Lists.AsReadOnly(converted);
  123. }
  124. }
  125. }