gapic-generator 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/CHANGELOG.md +43 -0
  4. data/CODE_OF_CONDUCT.md +43 -0
  5. data/CONTRIBUTING.md +28 -0
  6. data/LICENSE +202 -0
  7. data/README.md +72 -0
  8. data/bin/gapic-generator +103 -0
  9. data/bin/protoc-gen-ruby_gapic +33 -0
  10. data/default-rubocop.yml +10 -0
  11. data/gem_templates/binary.erb +20 -0
  12. data/gem_templates/dockerfile.erb +39 -0
  13. data/gem_templates/entrypoint.erb +24 -0
  14. data/gem_templates/gapic_sh.erb +97 -0
  15. data/gem_templates/gemfile.erb +8 -0
  16. data/gem_templates/gemspec.erb +36 -0
  17. data/gem_templates/generator.erb +37 -0
  18. data/gem_templates/gitignore.erb +10 -0
  19. data/gem_templates/rakefile.erb +29 -0
  20. data/gem_templates/readme.erb +69 -0
  21. data/gem_templates/rubocop.erb +16 -0
  22. data/gem_templates/shared/_header.erb +4 -0
  23. data/gem_templates/shared/_license.erb +13 -0
  24. data/gem_templates/shared/_warning.erb +1 -0
  25. data/gem_templates/test_generator.erb +13 -0
  26. data/gem_templates/test_helper.erb +25 -0
  27. data/gem_templates/version.erb +10 -0
  28. data/lib/gapic/file_formatter.rb +62 -0
  29. data/lib/gapic/formatting_utils.rb +109 -0
  30. data/lib/gapic/gem_builder.rb +98 -0
  31. data/lib/gapic/generator.rb +30 -0
  32. data/lib/gapic/generator/version.rb +21 -0
  33. data/lib/gapic/generators/base_generator.rb +91 -0
  34. data/lib/gapic/generators/default_generator.rb +101 -0
  35. data/lib/gapic/grpc_service_config/method_config.rb +49 -0
  36. data/lib/gapic/grpc_service_config/parser.rb +218 -0
  37. data/lib/gapic/grpc_service_config/parsing_error.rb +25 -0
  38. data/lib/gapic/grpc_service_config/retry_policy.rb +51 -0
  39. data/lib/gapic/grpc_service_config/service_config.rb +42 -0
  40. data/lib/gapic/path_template.rb +35 -0
  41. data/lib/gapic/path_template/parser.rb +83 -0
  42. data/lib/gapic/path_template/segment.rb +67 -0
  43. data/lib/gapic/resource_lookup.rb +91 -0
  44. data/lib/gapic/runner.rb +76 -0
  45. data/lib/gapic/schema.rb +17 -0
  46. data/lib/gapic/schema/api.rb +264 -0
  47. data/lib/gapic/schema/loader.rb +269 -0
  48. data/lib/gapic/schema/wrappers.rb +717 -0
  49. data/lib/google/api/annotations.pb.rb +39 -0
  50. data/lib/google/api/client.pb.rb +43 -0
  51. data/lib/google/api/field_behavior.pb.rb +51 -0
  52. data/lib/google/api/http.pb.rb +60 -0
  53. data/lib/google/api/resource.pb.rb +80 -0
  54. data/lib/google/longrunning/operations.pb.rb +115 -0
  55. data/lib/google/protobuf/any.pb.rb +40 -0
  56. data/lib/google/protobuf/compiler/plugin.pb.rb +72 -0
  57. data/lib/google/protobuf/descriptor.pb.rb +359 -0
  58. data/lib/google/protobuf/empty.pb.rb +36 -0
  59. data/lib/google/rpc/status.pb.rb +46 -0
  60. data/templates/default/gem/_version.erb +2 -0
  61. data/templates/default/gem/changelog.erb +3 -0
  62. data/templates/default/gem/gemfile.erb +4 -0
  63. data/templates/default/gem/gemspec.erb +37 -0
  64. data/templates/default/gem/gitignore.erb +20 -0
  65. data/templates/default/gem/license.erb +22 -0
  66. data/templates/default/gem/rakefile.erb +27 -0
  67. data/templates/default/gem/readme.erb +24 -0
  68. data/templates/default/gem/rubocop.erb +59 -0
  69. data/templates/default/gem/version.erb +6 -0
  70. data/templates/default/gem/yardopts.erb +12 -0
  71. data/templates/default/helpers/default_helper.rb +50 -0
  72. data/templates/default/helpers/filepath_helper.rb +38 -0
  73. data/templates/default/helpers/namespace_helper.rb +44 -0
  74. data/templates/default/helpers/presenter_helper.rb +24 -0
  75. data/templates/default/helpers/presenters/enum_presenter.rb +35 -0
  76. data/templates/default/helpers/presenters/enum_value_presenter.rb +33 -0
  77. data/templates/default/helpers/presenters/field_presenter.rb +146 -0
  78. data/templates/default/helpers/presenters/file_presenter.rb +53 -0
  79. data/templates/default/helpers/presenters/gem_presenter.rb +140 -0
  80. data/templates/default/helpers/presenters/message_presenter.rb +66 -0
  81. data/templates/default/helpers/presenters/method_presenter.rb +293 -0
  82. data/templates/default/helpers/presenters/package_presenter.rb +65 -0
  83. data/templates/default/helpers/presenters/resource_presenter.rb +92 -0
  84. data/templates/default/helpers/presenters/sample_presenter.rb +74 -0
  85. data/templates/default/helpers/presenters/service_presenter.rb +276 -0
  86. data/templates/default/layouts/_ruby.erb +20 -0
  87. data/templates/default/package.erb +6 -0
  88. data/templates/default/proto_docs/_enum.erb +13 -0
  89. data/templates/default/proto_docs/_message.erb +23 -0
  90. data/templates/default/proto_docs/_proto_file.erb +9 -0
  91. data/templates/default/proto_docs/proto_file.erb +6 -0
  92. data/templates/default/proto_docs/readme.erb +5 -0
  93. data/templates/default/service.erb +8 -0
  94. data/templates/default/service/client.erb +6 -0
  95. data/templates/default/service/client/_client.erb +137 -0
  96. data/templates/default/service/client/_config.erb +155 -0
  97. data/templates/default/service/client/_credentials.erb +21 -0
  98. data/templates/default/service/client/_helpers.erb +9 -0
  99. data/templates/default/service/client/_operations.erb +88 -0
  100. data/templates/default/service/client/_paths.erb +8 -0
  101. data/templates/default/service/client/_requires.erb +1 -0
  102. data/templates/default/service/client/_resource.erb +6 -0
  103. data/templates/default/service/client/_self_configure.erb +9 -0
  104. data/templates/default/service/client/_self_configure_defaults.erb +22 -0
  105. data/templates/default/service/client/_self_configure_retry_policy.erb +15 -0
  106. data/templates/default/service/client/method/_def.erb +21 -0
  107. data/templates/default/service/client/method/def/_options_defaults.erb +29 -0
  108. data/templates/default/service/client/method/def/_request.erb +6 -0
  109. data/templates/default/service/client/method/def/_request_normal.erb +4 -0
  110. data/templates/default/service/client/method/def/_request_streaming.erb +9 -0
  111. data/templates/default/service/client/method/def/_rescue.erb +1 -0
  112. data/templates/default/service/client/method/def/_response.erb +6 -0
  113. data/templates/default/service/client/method/def/_response_normal.erb +8 -0
  114. data/templates/default/service/client/method/def/_response_paged.erb +9 -0
  115. data/templates/default/service/client/method/docs/_error.erb +2 -0
  116. data/templates/default/service/client/method/docs/_request.erb +6 -0
  117. data/templates/default/service/client/method/docs/_request_field.erb +7 -0
  118. data/templates/default/service/client/method/docs/_request_normal.erb +20 -0
  119. data/templates/default/service/client/method/docs/_request_streaming.erb +5 -0
  120. data/templates/default/service/client/method/docs/_response.erb +6 -0
  121. data/templates/default/service/client/method/docs/_sample.erb +20 -0
  122. data/templates/default/service/client/method/docs/_sample_response.erb +24 -0
  123. data/templates/default/service/client/method/docs/_samples.erb +6 -0
  124. data/templates/default/service/client/method/docs/request_field/_arg.erb +10 -0
  125. data/templates/default/service/client/method/docs/request_field/_hash.erb +19 -0
  126. data/templates/default/service/client/method/docs/sample_response/_comment.erb +5 -0
  127. data/templates/default/service/client/method/docs/sample_response/_define.erb +2 -0
  128. data/templates/default/service/client/method/docs/sample_response/_loop.erb +12 -0
  129. data/templates/default/service/client/method/docs/sample_response/_print.erb +2 -0
  130. data/templates/default/service/client/method/docs/sample_response/_write_file.erb +2 -0
  131. data/templates/default/service/client/resource/_def.erb +6 -0
  132. data/templates/default/service/client/resource/_doc.erb +8 -0
  133. data/templates/default/service/client/resource/_multi.erb +28 -0
  134. data/templates/default/service/client/resource/_single.erb +11 -0
  135. data/templates/default/service/credentials.erb +6 -0
  136. data/templates/default/service/operations.erb +6 -0
  137. data/templates/default/service/paths.erb +6 -0
  138. data/templates/default/service/test/client.erb +24 -0
  139. data/templates/default/service/test/client_operations.erb +24 -0
  140. data/templates/default/service/test/method/_assert_response.erb +11 -0
  141. data/templates/default/service/test/method/_bidi.erb +100 -0
  142. data/templates/default/service/test/method/_client.erb +84 -0
  143. data/templates/default/service/test/method/_normal.erb +69 -0
  144. data/templates/default/service/test/method/_server.erb +85 -0
  145. data/templates/default/service/test/method/_setup.erb +21 -0
  146. data/templates/default/service/test/smoke.erb +12 -0
  147. data/templates/default/shared/_header.erb +4 -0
  148. data/templates/default/shared/_license.erb +21 -0
  149. data/templates/default/shared/_warning.erb +1 -0
  150. metadata +351 -0
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/path_template/parser"
18
+
19
+ module Gapic
20
+ # TODO: Enter docs
21
+ # Dooooooooocs!!!
22
+ module PathTemplate
23
+ # Parse a URI path template.
24
+ #
25
+ # @see https://tools.ietf.org/html/rfc6570 URI Template
26
+ #
27
+ # @param path_template [String] The URI path template to be parsed.
28
+ #
29
+ # @return [Array<PathTemplate::Segment|String>] The segments of the URI
30
+ # path template.
31
+ def self.parse path_template
32
+ Parser.new(path_template).segments
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/path_template/segment"
18
+
19
+ module Gapic
20
+ module PathTemplate
21
+ # A URI path template parser.
22
+ #
23
+ # @see https://tools.ietf.org/html/rfc6570 URI Template
24
+ #
25
+ # @!attribute [r] path_template
26
+ # @return [String] The URI path template to be parsed.
27
+ # @!attribute [r] segments
28
+ # @return [Array<Segment|String>] The segments of the parsed URI path
29
+ # template.
30
+ class Parser
31
+ # @private
32
+ # /((?<positional>\*\*?)|{(?<name>[^\/]+?)(?:=(?<template>.+?))?})/
33
+ PATH_TEMPLATE = %r{
34
+ (
35
+ (?<positional>\*\*?)
36
+ |
37
+ {(?<name>[^\/]+?)(?:=(?<template>.+?))?}
38
+ )
39
+ }x.freeze
40
+
41
+ attr_reader :path_template, :segments
42
+
43
+ # Create a new URI path template parser.
44
+ #
45
+ # @param path_template [String] The URI path template to be parsed.
46
+ def initialize path_template
47
+ @path_template = path_template
48
+ @segments = parse! path_template
49
+ end
50
+
51
+ protected
52
+
53
+ def parse! path_template
54
+ # segments contain either Strings or segment objects
55
+ segments = []
56
+ segment_pos = 0
57
+
58
+ while (match = PATH_TEMPLATE.match path_template)
59
+ # The String before the match needs to be added to the segments
60
+ segments << match.pre_match unless match.pre_match.empty?
61
+
62
+ segment, segment_pos = segment_and_pos_from_match match, segment_pos
63
+ segments << segment
64
+
65
+ path_template = match.post_match
66
+ end
67
+
68
+ # Whatever String is unmatched needs to be added to the segments
69
+ segments << path_template unless path_template.empty?
70
+
71
+ segments
72
+ end
73
+
74
+ def segment_and_pos_from_match match, pos
75
+ if match[:positional]
76
+ [Segment.new(pos, match[:positional]), pos + 1]
77
+ else
78
+ [Segment.new(match[:name], match[:template]), pos]
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Gapic
18
+ module PathTemplate
19
+ # A segment in a URI path template.
20
+ #
21
+ # @see https://tools.ietf.org/html/rfc6570 URI Template
22
+ #
23
+ # @!attribute [r] name
24
+ # @return [String, Integer] The name of a named segment, or the position
25
+ # of a positional segment.
26
+ # @!attribute [r] pattern
27
+ # @return [String, nil] The pattern of the segment, nil if not set.
28
+ class Segment
29
+ attr_reader :name, :pattern
30
+
31
+ def initialize name, pattern
32
+ @name = name
33
+ @pattern = pattern
34
+ end
35
+
36
+ # Determines if the segment is positional (has a number for a name).
37
+ #
38
+ # @return [Boolean]
39
+ def positional?
40
+ name.is_a? Integer
41
+ end
42
+
43
+ # Determines if the segment is named (has a string for a name).
44
+ #
45
+ # @return [Boolean]
46
+ def named?
47
+ !positional?
48
+ end
49
+
50
+ # Determines if the segment has a pattern. Positional segments always
51
+ # have a pattern. Named segments may have a pattern if provided in the
52
+ # URI path template.
53
+ #
54
+ # @return [Boolean]
55
+ def pattern?
56
+ !@pattern.nil?
57
+ end
58
+
59
+ # @private
60
+ def == other
61
+ return false unless other.is_a? self.class
62
+
63
+ (name == other.name) && (pattern == other.pattern)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2020 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Gapic
18
+ # TODO: Enter docs
19
+ # Dooooooooocs!!!
20
+ class ResourceLookup
21
+ # @private
22
+ def initialize service
23
+ @service = service
24
+ @api = service.parent.parent
25
+ end
26
+
27
+ # @private
28
+ def lookup!
29
+ resources = @api.files.flat_map { |file| lookup_file_resource_descriptors file }
30
+ resources.compact.uniq
31
+ end
32
+
33
+ # @private
34
+ def lookup_file_resource_descriptors file
35
+ resources = []
36
+ resources += file.resources.select { |resource| service_resource_types.include? resource.type }
37
+ resources += file.messages.flat_map { |message| lookup_message_resources_descriptors message }
38
+ resources
39
+ end
40
+
41
+ # @private
42
+ def service_resource_types
43
+ @service_resource_types ||= begin
44
+ @service.methods.flat_map do |method|
45
+ message_resource_types method.input
46
+ end.uniq
47
+ end
48
+ end
49
+
50
+ # @private
51
+ def message_resource_types message, seen_messages = []
52
+ return [] if seen_messages.include? message
53
+ seen_messages << message
54
+ resource_types = []
55
+ resource_types << message.resource.type if message.resource
56
+ resource_types += message.nested_messages.map do |nested_message|
57
+ message_resource_types nested_message, seen_messages
58
+ end
59
+ message.fields.each do |field|
60
+ resource_types << field.resource_reference.type if field.resource_reference
61
+ resource_types += message_resource_types field.message, seen_messages if field.message?
62
+ end
63
+ resource_types.flatten
64
+ end
65
+
66
+ # @private
67
+ def lookup_message_resources_descriptors message
68
+ resources = []
69
+
70
+ # We don't expect service_resource_types to iclude nil, so we can use message.resource&.type
71
+ resources << message.resource if service_resource_types.include? message.resource&.type
72
+
73
+ if message.nested_messages
74
+ resources += message.nested_messages.flat_map do |nested_message|
75
+ lookup_message_resources_descriptors nested_message
76
+ end
77
+ end
78
+
79
+ resources
80
+ end
81
+
82
+ # Lookup all resources for a given service.
83
+ #
84
+ # @param service [Gapic::Service] The service to lookup on.
85
+ #
86
+ # @return [Array<Google::Api::ResourceDescriptor>]
87
+ def self.for_service service
88
+ ResourceLookup.new(service).lookup!
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/generator"
18
+ require "gapic/schema"
19
+ require "google/protobuf/compiler/plugin.pb"
20
+
21
+ module Gapic
22
+ # TODO: Enter docs
23
+ # Dooooooooocs!!!
24
+ class Runner
25
+ attr_reader :request
26
+
27
+ # Initializes the runner.
28
+ # @param [Google::Protobuf::Compiler::CodeGeneratorRequest] request
29
+ def initialize request
30
+ @request = request
31
+ end
32
+
33
+ # Run protoc generation.
34
+ # @param [String] generator_type
35
+ # @return [Google::Protobuf::Compiler::CodeGeneratorResponse]
36
+ def run generator_type: nil
37
+ # Create an API Schema from the FileDescriptorProtos
38
+ api = Gapic::Schema::Api.new request
39
+
40
+ write_binary_file! api
41
+
42
+ # Retrieve generator type from protoc_options if not already provided.
43
+ generator_type ||= api.protoc_options["generator"]
44
+ # Find the generator for the generator type.
45
+ generator = Gapic::Generator.find generator_type
46
+
47
+ # Create and run the generator from the API.
48
+ output_files = generator.new(api).generate
49
+
50
+ # Create and write the response
51
+ Google::Protobuf::Compiler::CodeGeneratorResponse.new \
52
+ file: output_files
53
+ end
54
+
55
+ # Run protoc generation.
56
+ # @param [Google::Protobuf::Compiler::CodeGeneratorRequest] request
57
+ # @param [String] generator
58
+ # @return [Google::Protobuf::Compiler::CodeGeneratorResponse]
59
+ def self.run request, generator: nil
60
+ new(request).run generator_type: generator
61
+ end
62
+
63
+ private
64
+
65
+ def write_binary_file! api
66
+ return unless api.protoc_options["binary_output"]
67
+
68
+ # First, strip the binary_output parameter out so it doesn't get saved
69
+ binary_file = api.protoc_options.delete "binary_output"
70
+ request.parameter = api.protoc_parameter
71
+
72
+ # Write binary file if the binary_output option is set
73
+ File.binwrite binary_file, request.to_proto
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/schema/api"
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "yaml"
18
+ require "json"
19
+ require "gapic/schema/loader"
20
+ require "gapic/grpc_service_config/parser"
21
+
22
+ module Gapic
23
+ module Schema
24
+ # rubocop:disable Metrics/ClassLength
25
+
26
+ # A representation of a full API.
27
+ #
28
+ # @!attribute [r] files
29
+ # @return [Array<File>] The files represented by this API.
30
+ # @!attribute [r] services
31
+ # @return [<Array<Service>] The services seen across all files in this
32
+ # API.
33
+ # @!attribute [r] messages
34
+ # @return [Array<Message>] The top level messages seen across all files
35
+ # in this API.
36
+ # @!attribute [r] enums
37
+ # @return [Array<Enum>] The top level enums seen across all files in
38
+ # this API.
39
+ class Api
40
+ attr_accessor :request, :files
41
+
42
+ # Initializes an API object with the file descriptors that represent the
43
+ # API.
44
+ #
45
+ # @param request [Google::Protobuf::Compiler::CodeGeneratorRequest]
46
+ # The request object.
47
+ def initialize request
48
+ @request = request
49
+ loader = Loader.new
50
+ @files = request.proto_file.map do |fd|
51
+ loader.load_file fd, request.file_to_generate.include?(fd.name)
52
+ end
53
+ @files.each { |f| f.parent = self }
54
+ end
55
+
56
+ def lookup address
57
+ address = address.join "." if address.is_a? Array
58
+ @files.each do |f|
59
+ lookup = f.lookup address
60
+ return lookup if lookup
61
+ end
62
+ nil
63
+ end
64
+
65
+ def file_for address
66
+ address = address.join "." if address.is_a? Array
67
+ matching_files = @files.select { |f| f.lookup address }
68
+ matching_files.first
69
+ end
70
+
71
+ def fix_file_path str
72
+ str = String str
73
+ return str if configuration[:overrides].nil?
74
+ return str if configuration[:overrides][:file_path].nil?
75
+ configuration[:overrides][:file_path].fetch str, str
76
+ end
77
+
78
+ def fix_namespace str
79
+ str = String str
80
+ return str if configuration[:overrides].nil?
81
+ return str if configuration[:overrides][:namespace].nil?
82
+ configuration[:overrides][:namespace].fetch str, str
83
+ end
84
+
85
+ def generate_files
86
+ @files.select(&:generate?)
87
+ end
88
+
89
+ def services
90
+ @files.map(&:services).flatten
91
+ end
92
+
93
+ def messages
94
+ @files.map(&:messages).flatten
95
+ end
96
+
97
+ # Structured Hash representation of the parameter values.
98
+ # @return [Hash]
99
+ # A Hash of the request parameters.
100
+ def protoc_options
101
+ @protoc_options ||= begin
102
+ result = {}
103
+ parameters = parse_parameter request.parameter
104
+ parameters.each do |param_array|
105
+ key = param_array.first
106
+ next if key.empty?
107
+ value = param_array[1..-1]
108
+ value = value.first if value.size == 1
109
+ value = nil if value.empty?
110
+ result[str_to_key(key)] = value
111
+ end
112
+ result
113
+ end
114
+ end
115
+
116
+ # Reconstructed string representation of the protoc options
117
+ # @return [String]
118
+ def protoc_parameter
119
+ protoc_options.map do |k, v|
120
+ v = Array(v).map do |s|
121
+ s.gsub("\\", "\\\\\\\\").gsub(",", "\\\\,").gsub("=", "\\\\=")
122
+ end.join("=")
123
+ k = key_to_str k
124
+ "#{k}=#{v}"
125
+ end.join ","
126
+ end
127
+
128
+ # Structured representation of the samples configuration files.
129
+ # @return [Array<Hash>]
130
+ # An array of the sample file hashes.
131
+ def samples
132
+ @samples ||= begin
133
+ protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
134
+ YAML.load_file sample_path
135
+ end.compact
136
+ end
137
+ end
138
+
139
+ # Structured representation of the standalone samples configuration files.
140
+ # @return [Array<Hash>]
141
+ # An array of the standalone sample configuration hashes.
142
+ def standalone_samples
143
+ @standalone_samples ||= begin
144
+ supported_types = [
145
+ "com.google.api.codegen.SampleConfigProto",
146
+ "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
147
+ ]
148
+ supported_sample_types = [nil, "standalone"]
149
+ samples.select { |sample_file| supported_types.include? sample_file["type"] }
150
+ .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
151
+ .map { |sample_file| sample_file["samples"] }
152
+ .flatten.compact
153
+ .select { |sample_config| supported_sample_types.include? sample_config["sample_type"] }
154
+ end
155
+ end
156
+
157
+ # Structured representation of the standalone test samples configuration files.
158
+ # @return [Array<Hash>]
159
+ # An array of the standalone sample configuration hashes.
160
+ def standalone_test_samples
161
+ @standalone_test_samples ||= begin
162
+ samples.select { |sample| sample["type"] == "test/samples" }
163
+ .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
164
+ .map { |sample| sample["samples"] }
165
+ .flatten.compact
166
+ end
167
+ end
168
+
169
+ # Structured representation of the inline samples configuration files.
170
+ # @return [Array<Hash>]
171
+ # An array of the incode sample configuration hashes, sorted by sample_type.
172
+ def incode_samples
173
+ @incode_samples ||= begin
174
+ supported_types = [
175
+ "com.google.api.codegen.SampleConfigProto",
176
+ "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
177
+ ]
178
+ samples.select { |sample_file| supported_types.include? sample_file["type"] }
179
+ .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
180
+ .map { |sample_file| sample_file["samples"] }
181
+ .flatten.compact
182
+ .select { |sample_config| sample_config["sample_type"]&.start_with? "incode/" }
183
+ .sort_by { |sample_config| sample_config["sample_type"] }
184
+ end
185
+ end
186
+
187
+ # Structured Hash representation of the configuration file.
188
+ # @return [Hash]
189
+ # A Hash of the configuration values.
190
+ def configuration
191
+ @configuration ||= begin
192
+ config_file = protoc_options["configuration"]
193
+ config = config_file ? YAML.load_file(config_file) : {}
194
+ protoc_options.each do |k, v|
195
+ next if k == "configuration"
196
+ branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
197
+ config = deep_merge config, branch
198
+ end
199
+ config
200
+ end
201
+ end
202
+
203
+ # Raw parsed json of the combined grpc service config files if provided
204
+ # or an empty hash if no config was provided
205
+ def grpc_service_config_raw
206
+ @grpc_service_config_raw ||= begin
207
+ filenames = protoc_options["grpc_service_config"].to_s.split ";"
208
+ filenames.inject({}) do |running_hash, filename|
209
+ file_hash = JSON.parse ::File.read filename
210
+ deep_merge running_hash, file_hash
211
+ end
212
+ end
213
+ end
214
+
215
+ # Parsed grpc service config
216
+ def grpc_service_config
217
+ @grpc_service_config ||= begin
218
+ Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
219
+ end
220
+ end
221
+
222
+ private
223
+
224
+ def parse_parameter str
225
+ str.scan(/\\.|,|=|[^\\,=]+/)
226
+ .each_with_object([[String.new]]) do |tok, arr|
227
+ if tok == ","
228
+ arr.append [String.new]
229
+ elsif tok == "="
230
+ arr.last.append String.new
231
+ elsif tok.start_with? "\\"
232
+ arr.last.last << tok[1]
233
+ else
234
+ arr.last.last << tok
235
+ end
236
+ arr
237
+ end
238
+ end
239
+
240
+ def str_to_key str
241
+ str = str.to_s
242
+ str.start_with?(":") ? str[1..-1].to_sym : str
243
+ end
244
+
245
+ def key_to_str key
246
+ key.is_a?(::Symbol) ? ":#{key}" : key.to_s
247
+ end
248
+
249
+ def deep_merge left, right
250
+ left.merge right do |_k, lt, rt|
251
+ if lt.is_a?(Hash) && rt.is_a?(Hash)
252
+ deep_merge lt, rt
253
+ elsif lt.is_a?(Array) && rt.is_a?(Array)
254
+ lt + rt
255
+ else
256
+ rt
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ # rubocop:enable Metrics/ClassLength
263
+ end
264
+ end