google-apis-core 0.16.0 → 0.18.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea35d9daac9481979c51a054b42778f861d4d3fa7d1a8a384e1d955d9c49e0e9
4
- data.tar.gz: 9aae36827cc936b1125aeacd887beee6ca92012e8e2c48b4a429aaac925aa775
3
+ metadata.gz: adcaaf904d1c4e3e203b45c527c259c1be63aa675402247297a96ca087b5e14a
4
+ data.tar.gz: 6bafca376fc6569b0e8ff19071c1729e83310f55d3cb3b99e11d5440448ffd83
5
5
  SHA512:
6
- metadata.gz: 4591582657b1d9f1ff151cc74379113bc11a591e943a1257ee1371051db844023e2906234b5af3c8f55b1bb7c0ec6115c83f0a3258a3001f251aeba5419669bd
7
- data.tar.gz: 2ca6704eb8a9f1c86def9c644bf5868e1fe3b5442d3e1d6da9b5408e989d908ff4eb2ba07af56268ff2022e531c80bd26db435abd0031877345b9e740f668d42
6
+ metadata.gz: 4a24caabd4a3bfc09f9de6be416165fa6aa4b90f89b7ecf4f948801cba266c81e497f773fe25740a723056db708342a28eb36584a11dc43a436ca90e2eb95234
7
+ data.tar.gz: 4da89f87e45e5edf5c359aef57878e044c90411638c899744efe5235215fa576b2cd3eb46fa61b1678a4b57dda521b6f9fb386c8868a3b9118ddc494757f8a9a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Release History
2
2
 
3
+ ### 0.18.0 (2025-05-22)
4
+
5
+ #### Features
6
+
7
+ * Restart & delete resumable upload ([#21896](https://github.com/googleapis/google-api-ruby-client/issues/21896))
8
+
9
+ ### 0.17.0 (2025-04-30)
10
+
11
+ #### Features
12
+
13
+ * ruby 3.1 minimum, 3.4 default ([#22594](https://github.com/googleapis/google-api-ruby-client/issues/22594))
14
+ #### Bug Fixes
15
+
16
+ * Fixed a method redefined warning ([#21572](https://github.com/googleapis/google-api-ruby-client/issues/21572))
17
+ * Ensure compatibility with frozen string literals ([#21648](https://github.com/googleapis/google-api-ruby-client/issues/21648))
18
+
3
19
  ### 0.16.0 (2025-01-12)
4
20
 
5
21
  #### Features
@@ -151,7 +151,7 @@ module Google
151
151
 
152
152
  # HTTP client
153
153
  # @return [HTTPClient]
154
- attr_accessor :client
154
+ attr_writer :client
155
155
 
156
156
  # General settings
157
157
  # @return [Google::Apis::ClientOptions]
@@ -350,6 +350,36 @@ module Google
350
350
  true
351
351
  end
352
352
 
353
+ # Restarts An interrupted Resumable upload
354
+ # @param [String] bucket
355
+ # Name of the bucket where the upload is being performed.
356
+ # @param [IO, String] upload_source
357
+ # IO stream or filename containing content to upload
358
+ # @param [IO, String] upload_id
359
+ # unique id generated for an ongoing upload
360
+
361
+ def restart_resumable_upload(bucket, upload_source, upload_id, options: nil)
362
+ command = make_storage_upload_command(:put, 'b/{bucket}/o', options)
363
+ command.upload_source = upload_source
364
+ command.upload_id = upload_id
365
+ command.params['bucket'] = bucket unless bucket.nil?
366
+ execute_or_queue_command(command)
367
+ end
368
+
369
+ # Deletes An interrupted Resumable upload
370
+ # @param [String] bucket
371
+ # Name of the bucket where the upload is being performed.
372
+ # @param [IO, String] upload_id
373
+ # unique id generated for an ongoing upload
374
+
375
+ def delete_resumable_upload(bucket, upload_id, options: nil)
376
+ command = make_storage_upload_command(:delete, 'b/{bucket}/o', options)
377
+ command.upload_id = upload_id
378
+ command.params['bucket'] = bucket unless bucket.nil?
379
+ command.delete_upload = options[:delete_upload] unless options[:delete_upload].nil?
380
+ execute_or_queue_command(command)
381
+ end
382
+
353
383
  protected
354
384
 
355
385
  # Create a new upload command.
@@ -42,7 +42,7 @@ module Google
42
42
  end
43
43
 
44
44
  def read(length = nil, buf = nil)
45
- buf = buf ? buf.replace('') : ''
45
+ buf = buf ? buf.replace('') : +''
46
46
 
47
47
  begin
48
48
  io = @ios[@index]
@@ -46,7 +46,7 @@ module Google
46
46
  @download_io = File.open(download_dest, 'wb')
47
47
  @close_io_on_finish = true
48
48
  else
49
- @download_io = StringIO.new('', 'wb')
49
+ @download_io = StringIO.new(+'', 'wb')
50
50
  @close_io_on_finish = false
51
51
  end
52
52
  super
@@ -283,7 +283,7 @@ module Google
283
283
  # @yield [nil, err] if block given
284
284
  # @raise [StandardError] if no block
285
285
  def error(err, rethrow: false, &block)
286
- logger.debug { sprintf('Error - %s', PP.pp(err, '')) }
286
+ logger.debug { sprintf('Error - %s', PP.pp(err, +'')) }
287
287
  if err.is_a?(HTTPClient::BadResponseError)
288
288
  begin
289
289
  res = err.res
@@ -385,7 +385,7 @@ module Google
385
385
  end
386
386
 
387
387
  def safe_pretty_representation obj
388
- out = ""
388
+ out = +""
389
389
  printer = RedactingPP.new out, 79
390
390
  printer.guard_inspect_key { printer.pp obj }
391
391
  printer.flush
@@ -393,7 +393,7 @@ module Google
393
393
  end
394
394
 
395
395
  def safe_single_line_representation obj
396
- out = ""
396
+ out = +""
397
397
  printer = RedactingSingleLine.new out
398
398
  printer.guard_inspect_key { printer.pp obj }
399
399
  printer.flush
@@ -31,7 +31,7 @@ module Google
31
31
  end
32
32
 
33
33
  def to_io(boundary)
34
- part = ''
34
+ part = +''
35
35
  part << "--#{boundary}\r\n"
36
36
  part << "Content-Type: application/json\r\n"
37
37
  @header.each do |(k, v)|
@@ -59,7 +59,7 @@ module Google
59
59
  end
60
60
 
61
61
  def to_io(boundary)
62
- head = ''
62
+ head = +''
63
63
  head << "--#{boundary}\r\n"
64
64
  @header.each do |(k, v)|
65
65
  head << "#{k}: #{v}\r\n"
@@ -67,7 +67,7 @@ module Google
67
67
  head << "Content-Length: #{@length}\r\n" unless @length.nil?
68
68
  head << "Content-Transfer-Encoding: binary\r\n"
69
69
  head << "\r\n"
70
- Google::Apis::Core::CompositeIO.new(StringIO.new(head), @io, StringIO.new("\r\n"))
70
+ Google::Apis::Core::CompositeIO.new(StringIO.new(head), @io, StringIO.new(+"\r\n"))
71
71
  end
72
72
  end
73
73
 
@@ -126,7 +126,7 @@ module Google
126
126
  # @return [IO]
127
127
  # IO stream
128
128
  def assemble
129
- @parts << StringIO.new("--#{@boundary}--\r\n\r\n")
129
+ @parts << StringIO.new(+"--#{@boundary}--\r\n\r\n")
130
130
  Google::Apis::Core::CompositeIO.new(*@parts)
131
131
  end
132
132
  end
@@ -49,6 +49,14 @@ module Google
49
49
  # @return [Integer]
50
50
  attr_accessor :upload_chunk_size
51
51
 
52
+ # Unique upload_id of a resumable upload
53
+ # @return [String]
54
+ attr_accessor :upload_id
55
+
56
+ # Boolean Value to specify is a resumable upload is to be deleted or not
57
+ # @return [Boolean]
58
+ attr_accessor :delete_upload
59
+
52
60
  # Ensure the content is readable and wrapped in an IO instance.
53
61
  #
54
62
  # @return [void]
@@ -61,7 +69,6 @@ module Google
61
69
  # asserting that it already has a body. Form encoding is never used
62
70
  # by upload requests.
63
71
  self.body = '' unless self.body
64
-
65
72
  super
66
73
  if streamable?(upload_source)
67
74
  self.upload_io = upload_source
@@ -73,6 +80,8 @@ module Google
73
80
  self.upload_content_type = type&.content_type
74
81
  end
75
82
  @close_io_on_finish = true
83
+ elsif !upload_id.nil? && delete_upload
84
+ @close_io_on_finish = false
76
85
  else
77
86
  fail Google::Apis::ClientError, 'Invalid upload source'
78
87
  end
@@ -80,7 +89,7 @@ module Google
80
89
 
81
90
  # Close IO stream when command done. Only closes the stream if it was opened by the command.
82
91
  def release!
83
- upload_io.close if @close_io_on_finish
92
+ upload_io.close if @close_io_on_finish && !upload_io.nil?
84
93
  end
85
94
 
86
95
  # Execute the command, retrying as necessary
@@ -96,8 +105,16 @@ module Google
96
105
  prepare!
97
106
  opencensus_begin_span
98
107
  @upload_chunk_size = options.upload_chunk_size
108
+ if upload_id.nil?
109
+ res = do_retry :initiate_resumable_upload, client
110
+ elsif delete_upload && !upload_id.nil?
111
+ construct_resumable_upload_url upload_id
112
+ res = do_retry :cancel_resumable_upload, client
113
+ else
114
+ construct_resumable_upload_url upload_id
115
+ res = do_retry :reinitiate_resumable_upload, client
116
+ end
99
117
 
100
- do_retry :initiate_resumable_upload, client
101
118
  while @upload_incomplete
102
119
  res = do_retry :send_upload_command, client
103
120
  end
@@ -131,6 +148,22 @@ module Google
131
148
  error(e, rethrow: true)
132
149
  end
133
150
 
151
+ # Reinitiating resumable upload
152
+ def reinitiate_resumable_upload(client)
153
+ logger.debug { sprintf('Restarting resumable upload command to %s', url) }
154
+ check_resumable_upload client
155
+ upload_io.pos = @offset
156
+ end
157
+
158
+ # Making resumable upload url from upload_id
159
+ def construct_resumable_upload_url(upload_id)
160
+ query_params = query.dup
161
+ query_params['uploadType'] = RESUMABLE
162
+ query_params['upload_id'] = upload_id
163
+ resumable_upload_params = query_params.map { |key, value| "#{key}=#{value}" }.join('&')
164
+ @upload_url = "#{url}&#{resumable_upload_params}"
165
+ end
166
+
134
167
  # Send the actual content
135
168
  #
136
169
  # @param [HTTPClient] client
@@ -160,6 +193,9 @@ module Google
160
193
  @offset += current_chunk_size if @upload_incomplete
161
194
  success(result)
162
195
  rescue => e
196
+ logger.warn {
197
+ "error occured please use uploadId-#{response.headers['X-GUploader-UploadID']} to resume your upload"
198
+ } unless response.nil?
163
199
  upload_io.pos = @offset
164
200
  error(e, rethrow: true)
165
201
  end
@@ -182,6 +218,59 @@ module Google
182
218
  super(status, header, body)
183
219
  end
184
220
 
221
+ def check_resumable_upload(client)
222
+ # Setting up request header
223
+ request_header = header.dup
224
+ request_header[CONTENT_RANGE_HEADER] = "bytes */#{upload_io.size}"
225
+ request_header[CONTENT_LENGTH_HEADER] = '0'
226
+ # Initiating call
227
+ response = client.put(@upload_url, header: request_header, follow_redirect: true)
228
+ handle_resumable_upload_http_response_codes(response)
229
+ end
230
+
231
+ # Cancel resumable upload
232
+ def cancel_resumable_upload(client)
233
+ # Setting up request header
234
+ request_header = header.dup
235
+ request_header[CONTENT_LENGTH_HEADER] = '0'
236
+ # Initiating call
237
+ response = client.delete(@upload_url, header: request_header, follow_redirect: true)
238
+ handle_resumable_upload_http_response_codes(response)
239
+
240
+ if !@upload_incomplete && (400..499).include?(response.code.to_i)
241
+ @close_io_on_finish = true
242
+ true # method returns true if upload is successfully cancelled
243
+ else
244
+ logger.debug { sprintf("Failed to cancel upload session. Response: #{response.code} - #{response.body}") }
245
+ end
246
+
247
+ end
248
+
249
+ def handle_resumable_upload_http_response_codes(response)
250
+ code = response.code.to_i
251
+
252
+ case code
253
+ when 308
254
+ if response.headers['Range']
255
+ range = response.headers['Range']
256
+ @offset = range.split('-').last.to_i + 1
257
+ logger.debug { sprintf("Upload is incomplete. Bytes uploaded so far: #{range}") }
258
+ else
259
+ logger.debug { sprintf('No bytes uploaded yet.') }
260
+ end
261
+ @upload_incomplete = true
262
+ when 400..499
263
+ # Upload is canceled
264
+ @upload_incomplete = false
265
+ when 200, 201
266
+ # Upload is complete.
267
+ @upload_incomplete = false
268
+ else
269
+ logger.debug { sprintf("Unexpected response: #{response.code} - #{response.body}") }
270
+ @upload_incomplete = true
271
+ end
272
+ end
273
+
185
274
  def streamable?(upload_source)
186
275
  upload_source.is_a?(IO) || upload_source.is_a?(StringIO) || upload_source.is_a?(Tempfile)
187
276
  end
@@ -16,7 +16,7 @@ module Google
16
16
  module Apis
17
17
  module Core
18
18
  # Core version
19
- VERSION = "0.16.0".freeze
19
+ VERSION = "0.18.0".freeze
20
20
  end
21
21
  end
22
22
  end
@@ -43,7 +43,7 @@ module Google
43
43
  end
44
44
 
45
45
  def inspect
46
- extra = ""
46
+ extra = +""
47
47
  extra << " status_code: #{status_code.inspect}" unless status_code.nil?
48
48
  extra << " header: #{header.inspect}" unless header.nil?
49
49
  extra << " body: #{body.inspect}" unless body.nil?
@@ -41,7 +41,8 @@ module Google
41
41
  :quota_project,
42
42
  :query,
43
43
  :add_invocation_id_header,
44
- :upload_chunk_size)
44
+ :upload_chunk_size
45
+ )
45
46
 
46
47
  # General client options
47
48
  class ClientOptions
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-apis-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google LLC
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: representable
@@ -164,7 +164,7 @@ licenses:
164
164
  metadata:
165
165
  bug_tracker_uri: https://github.com/googleapis/google-api-ruby-client/issues
166
166
  changelog_uri: https://github.com/googleapis/google-api-ruby-client/tree/main/google-apis-core/CHANGELOG.md
167
- documentation_uri: https://googleapis.dev/ruby/google-apis-core/v0.16.0
167
+ documentation_uri: https://googleapis.dev/ruby/google-apis-core/v0.18.0
168
168
  source_code_uri: https://github.com/googleapis/google-api-ruby-client/tree/main/google-apis-core
169
169
  rdoc_options: []
170
170
  require_paths:
@@ -173,14 +173,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
173
173
  requirements:
174
174
  - - ">="
175
175
  - !ruby/object:Gem::Version
176
- version: '2.7'
176
+ version: '3.1'
177
177
  required_rubygems_version: !ruby/object:Gem::Requirement
178
178
  requirements:
179
179
  - - ">="
180
180
  - !ruby/object:Gem::Version
181
181
  version: '0'
182
182
  requirements: []
183
- rubygems_version: 3.6.2
183
+ rubygems_version: 3.6.9
184
184
  specification_version: 4
185
185
  summary: Common utility and base classes for legacy Google REST clients
186
186
  test_files: []