gapic-generator 0.7.2 → 0.7.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/lib/gapic/generator/version.rb +1 -1
  4. data/lib/gapic/generators/default_generator.rb +8 -5
  5. data/lib/gapic/generators/default_generator_parameters.rb +8 -4
  6. data/lib/gapic/presenters.rb +2 -0
  7. data/lib/gapic/presenters/field_presenter.rb +44 -0
  8. data/lib/gapic/presenters/gem_presenter.rb +4 -1
  9. data/lib/gapic/presenters/method_presenter.rb +32 -16
  10. data/lib/gapic/presenters/method_rest_presenter.rb +186 -0
  11. data/lib/gapic/presenters/package_presenter.rb +18 -0
  12. data/lib/gapic/presenters/service_presenter.rb +42 -4
  13. data/lib/gapic/presenters/service_rest_presenter.rb +157 -0
  14. data/lib/gapic/schema/api.rb +44 -16
  15. data/lib/gapic/schema/request_param_parser.rb +44 -10
  16. data/templates/default/lib/_package.erb +11 -1
  17. data/templates/default/lib/_service.erb +31 -1
  18. data/templates/default/lib/rest/_rest.erb +11 -0
  19. data/templates/default/service/rest.erb +6 -0
  20. data/templates/default/service/rest/client.erb +6 -0
  21. data/templates/default/service/rest/client/_client.erb +115 -0
  22. data/templates/default/service/rest/client/_config.erb +74 -0
  23. data/templates/default/service/rest/client/_requires.erb +1 -0
  24. data/templates/default/service/rest/client/method/_def.erb +18 -0
  25. data/templates/default/service/rest/client/method/def/_options_defaults.erb +14 -0
  26. data/templates/default/service/rest/client/method/def/_rescue.erb +3 -0
  27. data/templates/default/service/rest/client/method/def/_response_normal.erb +17 -0
  28. data/templates/default/service/rest/client/method/docs/_error.erb +2 -0
  29. data/templates/default/service/rest/client/method/docs/_request.erb +27 -0
  30. data/templates/default/service/rest/client/method/docs/_result.erb +6 -0
  31. data/templates/default/service/rest/grpc_transcoding.erb +6 -0
  32. data/templates/default/service/rest/grpc_transcoding/_grpc_transcoding.erb +9 -0
  33. data/templates/default/service/rest/grpc_transcoding/method/_def.erb +21 -0
  34. data/templates/default/service/rest/grpc_transcoding/method/def/_query_string_param.erb +8 -0
  35. metadata +22 -3
@@ -54,7 +54,10 @@ module Gapic
54
54
  namespace.split("::").last
55
55
  end
56
56
 
57
+ ##
57
58
  # Services whose clients should be generated in this package namespace.
59
+ # @return [Enumerable<Gapic::Presenters::ServicePresenter>]
60
+ #
58
61
  def services
59
62
  @services ||= begin
60
63
  files = @api.generate_files.select { |f| f.package == @package }
@@ -117,6 +120,21 @@ module Gapic
117
120
  services: services.map { |s| [s.grpc_service_name, s.drift_manifest] }.to_h
118
121
  }
119
122
  end
123
+
124
+ ##
125
+ # How comments in the generated libraries refer to the GRPC client
126
+ # if no REST code is generated, this should just be "client",
127
+ # if REST code is generated, this should be disambiguated into the "GRPC client"
128
+ #
129
+ # Since we are using first service for an indication of whether package generates
130
+ # REST code, it's OK to defer this to the first service as well.
131
+ # For packages with no services the value of this does not really matter as
132
+ # no client generation docs will be generated.
133
+ #
134
+ # @return [String]
135
+ def grpc_client_designation
136
+ services.first&.grpc_client_designation || ""
137
+ end
120
138
  end
121
139
  end
122
140
  end
@@ -27,11 +27,15 @@ module Gapic
27
27
  include Gapic::Helpers::FilepathHelper
28
28
  include Gapic::Helpers::NamespaceHelper
29
29
 
30
+ # @return [Gapic::Presenters::ServiceRestPresenter]
31
+ attr_reader :rest
32
+
30
33
  def initialize gem_presenter, api, service, parent_service: nil
31
34
  @gem_presenter = gem_presenter
32
35
  @api = api
33
36
  @service = service
34
37
  @parent_service = parent_service
38
+ @rest = ServiceRestPresenter.new self, api
35
39
  end
36
40
 
37
41
  def gem
@@ -46,10 +50,11 @@ module Gapic
46
50
  PackagePresenter.new @gem_presenter, @api, @service.parent.package
47
51
  end
48
52
 
53
+ ##
54
+ # @return [Enumerable<Gapic::Presenters::MethodPresenter>]
55
+ #
49
56
  def methods
50
- @methods ||= begin
51
- @service.methods.map { |m| MethodPresenter.new self, @api, m }
52
- end
57
+ @methods ||= @service.methods.map { |m| MethodPresenter.new self, @api, m }
53
58
  end
54
59
 
55
60
  def address
@@ -271,6 +276,29 @@ module Gapic
271
276
  ruby_file_path @api, "#{service_name_full}::#{paths_name}"
272
277
  end
273
278
 
279
+ def generate_rest_clients?
280
+ @api.generate_rest_clients?
281
+ end
282
+
283
+ def generate_grpc_clients?
284
+ @api.generate_grpc_clients?
285
+ end
286
+
287
+ ##
288
+ # @return [Boolean] whether this service contains any methods with REST bindings
289
+ #
290
+ def methods_rest_bindings?
291
+ methods_rest_bindings.any?
292
+ end
293
+
294
+ ##
295
+ # @return [Enumerable<Gapic::Presenters::MethodPresenter>]
296
+ # List of mods for which REST bindings are present and REST methods can be generated
297
+ #
298
+ def methods_rest_bindings
299
+ methods.select { |method| method.rest.path? && method.rest.verb? }
300
+ end
301
+
274
302
  def test_client_file_path
275
303
  service_file_path.sub ".rb", "_test.rb"
276
304
  end
@@ -361,12 +389,22 @@ module Gapic
361
389
  # their names are returned together in an array.
362
390
  # For Ruby currently we have 1:1 proto to code
363
391
  # correspondence for methods, so our generation is easier
364
- methods: methods.map { |m| [m.grpc_method_name, [m.name]] }.to_h
392
+ rpcs: methods.map { |m| [m.grpc_method_name, m.drift_manifest] }.to_h
365
393
  }
366
394
  }
367
395
  }
368
396
  end
369
397
 
398
+ ##
399
+ # How comments in the generated libraries refer to the GRPC client
400
+ # if no REST code is generated, this should just be "client",
401
+ # if REST code is generated, this should be disambiguated into the "GRPC client"
402
+ #
403
+ # @return [String]
404
+ def grpc_client_designation
405
+ generate_rest_clients? ? "GRPC client" : "client"
406
+ end
407
+
370
408
  private
371
409
 
372
410
  def default_config key
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 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 "active_support/inflector"
18
+ require "gapic/helpers/filepath_helper"
19
+ require "gapic/helpers/namespace_helper"
20
+
21
+ module Gapic
22
+ module Presenters
23
+ ##
24
+ # A presenter for proto service (REST submethods)
25
+ #
26
+ class ServiceRestPresenter
27
+ include Gapic::Helpers::FilepathHelper
28
+ include Gapic::Helpers::NamespaceHelper
29
+
30
+ ##
31
+ # @param main_service [Gapic::Presenters::ServicePresenter]
32
+ # @param api [Gapic::Schema::Api]
33
+ #
34
+ def initialize main_service, api
35
+ @main_service = main_service
36
+ @api = api
37
+ end
38
+
39
+ ##
40
+ # @return [String]
41
+ #
42
+ def service_name_full
43
+ fix_namespace api, "#{main_service.service_name_full}::Rest"
44
+ end
45
+
46
+ ##
47
+ # @return [String]
48
+ #
49
+ def client_name
50
+ main_service.client_name
51
+ end
52
+
53
+ ##
54
+ # @return [String]
55
+ #
56
+ def client_name_full
57
+ fix_namespace api, "#{service_name_full}::#{client_name}"
58
+ end
59
+
60
+ ##
61
+ # @return [String]
62
+ #
63
+ def client_require
64
+ ruby_file_path api, client_name_full
65
+ end
66
+
67
+ ##
68
+ # @return [String]
69
+ #
70
+ def client_file_path
71
+ "#{client_require}.rb"
72
+ end
73
+
74
+ def create_client_call
75
+ "#{client_name_full}.new"
76
+ end
77
+
78
+ ##
79
+ # @return [String]
80
+ #
81
+ def service_stub_name
82
+ "ServiceStub"
83
+ end
84
+
85
+ ##
86
+ # @return [String]
87
+ #
88
+ def service_stub_name_full
89
+ fix_namespace api, "#{service_name_full}::#{service_stub_name}"
90
+ end
91
+
92
+ ##
93
+ # @return [String]
94
+ #
95
+ def service_stub_require
96
+ ruby_file_path api, service_stub_name_full
97
+ end
98
+
99
+ ##
100
+ # @return [String]
101
+ #
102
+ def service_stub_file_path
103
+ "#{service_stub_require}.rb"
104
+ end
105
+
106
+ ##
107
+ # @return [String]
108
+ #
109
+ def service_rest_require
110
+ ruby_file_path api, service_name_full
111
+ end
112
+
113
+ ##
114
+ # @return [String]
115
+ #
116
+ def service_rest_file_path
117
+ "#{service_rest_require}.rb"
118
+ end
119
+
120
+ ##
121
+ # @return [String]
122
+ #
123
+ def transcoding_helper_name
124
+ "GrpcTranscoding"
125
+ end
126
+
127
+ ##
128
+ # @return [String]
129
+ #
130
+ def transcoding_helper_name_full
131
+ fix_namespace api, "#{service_name_full}::#{transcoding_helper_name}"
132
+ end
133
+
134
+ ##
135
+ # @return [String]
136
+ #
137
+ def transcoding_helper_require
138
+ ruby_file_path api, transcoding_helper_name_full
139
+ end
140
+
141
+ ##
142
+ # @return [String]
143
+ #
144
+ def transcoding_helper_file_path
145
+ "#{transcoding_helper_require}.rb"
146
+ end
147
+
148
+
149
+ private
150
+
151
+ # @return [Gapic::Presenters::ServicePresenter]
152
+ attr_reader :main_service
153
+ # @return [Gapic::Schema::Api]
154
+ attr_reader :api
155
+ end
156
+ end
157
+ end
@@ -144,11 +144,9 @@ module Gapic
144
144
  # @return [Array<Hash>]
145
145
  # An array of the sample file hashes.
146
146
  def samples
147
- @samples ||= begin
148
- protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
149
- YAML.load_file sample_path
150
- end.compact
151
- end
147
+ @samples ||= protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
148
+ YAML.load_file sample_path
149
+ end.compact
152
150
  end
153
151
 
154
152
  # Structured representation of the standalone samples configuration files.
@@ -174,10 +172,10 @@ module Gapic
174
172
  # An array of the standalone sample configuration hashes.
175
173
  def standalone_test_samples
176
174
  @standalone_test_samples ||= begin
177
- samples.select { |sample| sample["type"] == "test/samples" }
178
- .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
179
- .map { |sample| sample["samples"] }
180
- .flatten.compact
175
+ test_samples = samples.select { |sample| sample["type"] == "test/samples" }
176
+ test_samples.select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
177
+ .map { |sample| sample["samples"] }
178
+ .flatten.compact
181
179
  end
182
180
  end
183
181
 
@@ -231,6 +229,24 @@ module Gapic
231
229
  configuration[:generate_path_helpers_output] ||= false
232
230
  end
233
231
 
232
+ # Whether to generate REST clients
233
+ def generate_rest_clients?
234
+ return false if configuration[:transports].nil?
235
+ configuration[:transports].include? "rest"
236
+ end
237
+
238
+ # Whether to generate GRPC clients
239
+ def generate_grpc_clients?
240
+ return true if configuration[:transports].nil?
241
+ configuration[:transports].include? "grpc"
242
+ end
243
+
244
+ # Whether to generate gapic metadata (drift manifest) file
245
+ # @return [Boolean]
246
+ def generate_metadata
247
+ configuration[:generate_metadata] ||= false
248
+ end
249
+
234
250
  # Whether the override_proto_namespaces parameter was given in the configuration
235
251
  def override_proto_namespaces_defined?
236
252
  configuration.key? :override_proto_namespaces
@@ -260,9 +276,7 @@ module Gapic
260
276
 
261
277
  # Parsed grpc service config
262
278
  def grpc_service_config
263
- @grpc_service_config ||= begin
264
- Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
265
- end
279
+ @grpc_service_config ||= Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
266
280
  end
267
281
 
268
282
  # Get a resource given its type string
@@ -272,10 +286,8 @@ module Gapic
272
286
 
273
287
  # Given a service, find all common services that use it as a delegate.
274
288
  def common_services_for delegate
275
- @delegate_to_common ||= begin
276
- (configuration[:common_services] || {}).each_with_object({}) do |(c, d), mapping|
277
- (mapping[d] ||= []) << c
278
- end
289
+ @delegate_to_common ||= (configuration[:common_services] || {}).each_with_object({}) do |(c, d), mapping|
290
+ (mapping[d] ||= []) << c
279
291
  end
280
292
  all_services = services
281
293
  @delegate_to_common.fetch(delegate.address.join("."), []).map do |addr|
@@ -292,6 +304,22 @@ module Gapic
292
304
  services.find { |s| s.address == addr }
293
305
  end
294
306
 
307
+ ##
308
+ # Whether configuration has an override for the wrapper gem name
309
+ # @return [Boolean]
310
+ def wrapper_gem_name_override?
311
+ configuration.key?(:overrides) &&
312
+ configuration[:overrides].key?(:wrapper_gem_name)
313
+ end
314
+
315
+ ##
316
+ # An override for the wrapper gem name in the configuration
317
+ # @return [String, Nil]
318
+ def wrapper_gem_name_override
319
+ return nil unless wrapper_gem_name_override?
320
+ configuration[:overrides][:wrapper_gem_name]
321
+ end
322
+
295
323
  private
296
324
 
297
325
  # Perform a variety of sanity checks on the data, and prints errors to
@@ -67,14 +67,13 @@ module Gapic
67
67
  param_name_input = unescape param_name_input_esc
68
68
  param_type, param_config_name = param_schema.schema_name_type_for param_name_input
69
69
 
70
- if param_type == :bool && !["true", "false"].include?(unescape(value_str))
71
- error_str = "WARNING: parameter #{param_name_input} (recognised as bool " \
72
- "#{param_config_name}) will be discarded because of " \
73
- "invalid value. Value should be either 'true' or 'false'."
74
- error_output&.puts error_str
75
- end
76
-
77
- param_value = parse_param_value param_type, value_str
70
+ param_value = parse_validate_param_value(
71
+ param_type,
72
+ param_name_input,
73
+ param_config_name,
74
+ value_str,
75
+ error_output
76
+ )
78
77
 
79
78
  if param_value
80
79
  RequestParameter.new param_val_input_str, param_name_input_esc, value_str, param_config_name, param_value
@@ -92,13 +91,48 @@ module Gapic
92
91
 
93
92
  private
94
93
 
94
+ # Parses and validates param value depending on type and name
95
+ # @param param_type [Symbol] type of the parameter
96
+ # @param param_name_input [String] name of the parameter as given in the config
97
+ # @param param_config_name [String] canonical configuration name of the parameter
98
+ # @param value_str [String] string representation of parameter's value
99
+ # @param error_output [IO] Stream to write outputs to.
100
+ # @return [String,Array<String>,Hash{String => String}]
101
+ def parse_validate_param_value param_type, param_name_input, param_config_name, value_str, error_output
102
+ if param_type == :bool && !["true", "false"].include?(unescape(value_str))
103
+ error_str = "WARNING: parameter #{param_name_input} (recognised as bool " \
104
+ "#{param_config_name}) will be discarded because of " \
105
+ "invalid value. Value should be either 'true' or 'false'."
106
+ error_output&.puts error_str
107
+ end
108
+
109
+ param_value = parse_param_value param_type, value_str
110
+
111
+ if param_config_name == ":transports"
112
+ allowed_transports = ["grpc", "rest"]
113
+ noncompliant_values = param_value.reject { |pv| allowed_transports.include? pv }
114
+ if noncompliant_values.any?
115
+ noncompliant_values_list = noncompliant_values.join ", "
116
+ error_str = "WARNING: parameter #{param_name_input} (recognised as string array " \
117
+ "#{param_config_name}) will be discarded because "\
118
+ "it contains invalid values: #{noncompliant_values_list}. "\
119
+ "#{param_config_name} can only contain 'grpc' and/or 'rest' or be empty."
120
+ error_output&.puts error_str
121
+ param_value = nil
122
+ end
123
+ end
124
+
125
+ param_value
126
+ end
127
+
95
128
  # Parses param value depending on type
96
- # @param param_type [Symbol]
97
- # @param value_str [String]
129
+ # @param param_type [Symbol] type of the parameter
130
+ # @param value_str [String] string representation of parameter's value
98
131
  # @return [String,Array<String>,Hash{String => String}]
99
132
  def parse_param_value param_type, value_str
100
133
  case param_type
101
134
  when :array
135
+ return [] if value_str.empty?
102
136
  # elements in the arrays are concatenated by `;`
103
137
  # e.g. foo;bar;baz
104
138
  array_value_strings = split_by_unescaped value_str, ";"
@@ -6,13 +6,23 @@ require "<%= service.service_require %>"
6
6
  require "<%= package.gem.version_require %>"
7
7
  <% end %>
8
8
  <%- unless package.empty? -%>
9
+ <%- if package.services.first.generate_grpc_clients? -%>
9
10
  ##
10
- # To load this package, including all its services, and instantiate a client:
11
+ # To load this package, including all its services, and instantiate a <%= package.grpc_client_designation %>:
11
12
  #
12
13
  # require "<%= package.package_require %>"
13
14
  # client = <%= package.services.first.create_client_call %>
14
15
  #
15
16
  <%- end -%>
17
+ <%- if package.services.first.generate_rest_clients? -%>
18
+ ##
19
+ # To load this package, including all its services, and instantiate a REST client:
20
+ #
21
+ # require "<%= package.package_require %>"
22
+ # client = <%= package.services.first.rest.create_client_call %>
23
+ #
24
+ <%- end -%>
25
+ <%- end -%>
16
26
  module <%= package.module_name %>
17
27
  end
18
28
  <% @footer = capture do %>