
    	B                     p   S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSKrSSK	J
r  SSKJr  SSKJr  SSKJ
r
  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKr " S S\R6                  " \R8                  \5      5      r " S S\5      r " S S\5      r  " S S\ 5      r! " S S\ 5      r"g)z&Upload workflow using gRPC API client.    )absolute_import)division)unicode_literalsN)
retry_util)	grpc_util)metadata_util)	hash_util)resource_reference)	copy_util)log)
properties)scaled_integerc                   r    \ rS rSrSr  SS jrS rS rS rS r	SS	 jr
S
 r\R                  S 5       rSrg)_Upload'   z1Base class shared by different upload strategies.Nc                 t    Xl         X l        X0l        X@l        X`l        X`l        SU l        SU l        XPl        g)at  Initializes _Upload.

Args:
  client (StorageClient): The GAPIC client.
  source_stream (io.IOBase): Yields bytes to upload.
  destination_resource (resource_reference.ObjectResource|UnknownResource):
    Metadata for the destination object.
  request_config (gcs_api.GcsRequestConfig): Tracks additional request
    preferences.
  source_resource (FileObjectResource|ObjectResource|None): Contains the
    source StorageUrl and source object metadata for daisy chain transfers.
    Can be None if source is pure stream.
  start_offset (int): The offset from the beginning of the object at
    which the data should be written.
FN)	_client_source_stream_destination_resource_request_config_start_offset_uploaded_so_far_source_stream_finished_chunk_size_source_resource)selfclientsource_streamdestination_resourcerequest_configsource_resourcestart_offsets          5lib/googlecloudsdk/api_lib/storage/gcs_grpc/upload.py__init___Upload.__init__*   s=    0 L'!5)%(#(D D+    c                     U R                   R                  bU  U R                   R                  R                  b4  [        R                  " U R                   R                  R                  5      $ g)zReturns MD5 hash bytes sequence from resource args if given.

Returns:
  bytes|None: MD5 hash bytes sequence if MD5 string was given, otherwise
  None.
N)r   resource_argsmd5_hashr	   get_bytes_from_base64_stringr   s    r#   _get_md5_hash_if_given_Upload._get_md5_hash_if_givenN   sY     	**6  ..77C33



,
,
5
57 7r&   c                     U R                   U l        U R                  R                  U R                   [        R
                  5        SU l        g NF)r   r   r   seekosSEEK_SETr   r+   s    r#   _initialize_generator_Upload._initialize_generator[   s:     !..DT//=#(D r&   c           	   #     #    Sn[        XR                  R                  R                  5      (       a  UnSnOSnUnU R	                  5          U R
                  R                  U R                  R                  R                  R                  R                  5      nU(       d  SnOSnSnU(       a  SnSnO3U R                  R                  R                  U R                  5       S9nSnU R                  R                  R                  UUU R                  U R                  R                  R                  US9UUS9v   U =R                  [        U5      -  sl        U(       a  SU l        gU R"                  c  GM-  [        U5      U R                  R                  R                  R                  R                  :H  nU R                  U R$                  -
  n	U(       a  XR"                  :  a  gGM  7f)a  Yields the WriteObjectRequest for each chunk of the source stream.

The amount_of_data_sent_so_far is equal to the number of bytes read
from the source stream.

If _chunk_size is not None, this function will yield the WriteObjectRequest
object until the amount_of_data_sent_so_far is equal to or greater than the
value of the new _chunk_size and the length of data sent in the last
WriteObjectRequest is equal to MAX_WRITE_CHUNK_BYTES, or if there are no
data in the source stream.

MAX_WRITE_CHUNK_BYTES is a multiple 256 KiB.

Clients must only send data that is a multiple of 256 KiB per message,
unless the object is being finished with``finish_write`` set to ``true``.

This means that if amount_of_data_sent_so_far >= _chunk_size,
it must also be ensured before stopping yielding
requests(WriteObjectRequest) that all requests have sent
data multiple of 256 KiB, in other words length of data % 256 KiB is 0.

The source stream data is read in chunks of MAX_WRITE_CHUNK_BYTES, that
means that each request yielded will send data of size
MAX_WRITE_CHUNK_BYTES, except if there is a last request before the final
request(``finish_write`` set to ``true``) where the data length is less
than MAX_WRITE_CHUNK_BYTES, this means if the length of data in the last
request yielded is equal to MAX_WRITE_CHUNK_BYTES, all requests sent before
have sent data of size MAX_WRITE_CHUNK_BYTES, therefore all requests have
sent data that is multiple of 256 KiB, thus satisfying the condition
stated before. If the the length of data in the last request yielded is not
equal to MAX_WRITE_CHUNK_BYTES, then stop when there are no data
in the source stream(the final request is sent).

Otherwise if _chunk_size is None, it will yield all WriteObjectRequest
objects until there are no data in the source stream.

Args:
  first_message (WriteObjectSpec|str): WriteObjectSpec for Simple uploads,
  str that is the upload id for Resumable and Streaming uploads.

Yields:
  (googlecloudsdk.generated_clients.gapic_clients.storage_v2.types.WriteObjectRequest)
  WriteObjectRequest instance.
FNT)r)   )content)write_object_spec	upload_idwrite_offsetchecksummed_dataobject_checksumsfinish_write)
isinstancer   typesWriteObjectSpecr3   r   readServiceConstantsValuesMAX_WRITE_CHUNK_BYTESObjectChecksumsr,   WriteObjectRequestr   ChecksummedDatalenr   r   r   )
r   first_messagefirst_request_doner7   r8   datar;   r<   0is_length_of_data_equal_to_max_write_chunk_bytesamount_of_data_sent_so_fars
             r#   &_upload_write_object_request_generator._Upload._upload_write_object_request_generatorc   s    Z -!3!3!C!CDD'ii 
  %%
,,


-
-
4
4
J
Jd  ! 		  <<--==002 > 
 LL11-,,<<--==d=K+# 2   s4y(	'+$				!
 d)\\0077MMN 7 $(#8#84;M;M#M 
:(,<,<<c s   G*G,c                     [        U R                  [        R                  5      (       d  gU R                  R                  (       d  g[
        R                  " U R                  R                  5      Ul        g)a  Copies metadata from _source_resource to object_metadata.

It is copied if _source_resource is an instance of ObjectResource, this is
in case a daisy chain copy is performed.

Args:
  object_metadata (gapic_clients.storage_v2.types.storage.Object): Existing
    object metadata.
N)r=   r   r
   ObjectResourcecustom_fieldscopydeepcopymetadata)r   object_metadatas     r#   *_set_metadata_if_source_is_object_resource2_Upload._set_metadata_if_source_is_object_resource   sS     d++-?-N-NOO  ..#}}++ -Or&   c                    U R                   R                  R                  U R                  R                  R
                  [        R                  " U R                  R                  R                  5      US9nU R                  U5        [        R                  " X R                  U R                  5        U R                   R                  R                  U[        R                   " U R                  5      U R                  R"                  US9$ )zReturns the WriteObjectSpec instance.

Args:
  size (int|None): Expected object size in bytes.

Returns:
  (gapic_clients.storage_v2.types.storage.WriteObjectSpec) The
  WriteObjectSpec instance.
)namebucketsize)resourceif_generation_matchif_metageneration_matchobject_size)r   r>   Objectr   storage_urlresource_namer   get_full_bucket_namebucket_namerV   r   *update_object_metadata_from_request_configr   r   r?   r   get_generation_match_value!precondition_metageneration_match)r   r[   destination_objects      r#   _get_write_object_spec_Upload._get_write_object_spec   s     ++22''33AA--&&22>>@	 3  	33 <<00$2G2G <<--#%@@  
   BB .  r&   c                     U R                   R                  R                  U R                  US9[        R
                  " [        R                  " U R                  R                  R                  5      5      S9$ )zCalls write object api method with routing header.

Args:
  first_message (WriteObjectSpec|str): WriteObjectSpec for Simple uploads.
Returns:
  (gapic_clients.storage_v2.types.WriteObjectResponse) Request response.
)rH   )requestsrT   )r   storagewrite_objectrM   r   get_bucket_name_routing_headerr   rc   r   ra   rd   )r   rH   s     r#   _call_write_object_Upload._call_write_object  so     <<,,<<' = 
 ==****66BB
	 - 	 	r&   c                     [         e)z=Performs an upload and returns and returns an Object message.)NotImplementedErrorr+   s    r#   run_Upload.run  s
     r&   )	r   r   r   r   r   r   r   r   r   )Nr   N)__name__
__module____qualname____firstlineno____doc__r$   r,   r3   rM   rV   ri   rp   abcabstractmethodrt   __static_attributes__ r&   r#   r   r   '   sN    9 ",H)iV-*!F&  r&   r   c                   <    \ rS rSrSr\R                  S 5       rSrg)SimpleUploadi  z(Uploads an object with a single request.c                     U R                  U R                  R                  R                  5      nU R	                  U5      $ )zUploads the object in non-resumable mode.

Returns:
  (gapic_clients.storage_v2.types.WriteObjectResponse) A WriteObjectResponse
  instance.
)ri   r   r(   r[   rp   )r   r7   s     r#   rt   SimpleUpload.run"  sB     33**// "" r&   r   N)	rw   rx   ry   rz   r{   r   grpc_default_retryerrt   r~   r   r&   r#   r   r     s    0"" #r&   r   c                   >    \ rS rSrSrS rS r  S
S jrS rS r	S	r
g)RecoverableUploadi2  z7Common logic for strategies allowing retries in-flight.c                     U R                  5       nU R                  R                  R                  US9nU R                  R                  R                  US9R                  nSU l        U$ )zSets up the upload session and returns the upload id.

This method sets the start offset to 0.

Returns:
  (str) Session URI for resumable upload operation.
)r7   requestr   )ri   r   r>   StartResumableWriteRequestrm   start_resumable_writer8   r   )r   r7   r   r8   s       r#   _initialize_upload$RecoverableUpload._initialize_upload5  so     335ll  ;;+ < G $$:: ; " Dr&   c                     U R                   R                  R                  US9nU R                   R                  R	                  US9R
                  $ )a	  Returns the amount of data persisted on the server.

Args:
  upload_id (str): Session URI for resumable upload operation.
Returns:
  (int) The total number of bytes that have been persisted for an object
  on the server. This value can be used as the write_offset.
)r8   r   )r   r>   QueryWriteStatusRequestrm   query_write_statuspersisted_size)r   r8   r   s      r#   _get_write_offset#RecoverableUpload._get_write_offsetJ  sR     ll  88 9 G <<22 3 nr&   Nc                     [         R                  " X#XE5      (       d  gU R                  U5      nX`R                  :  nU(       a  X`l        g)NFT)r   is_retriabler   r   )r   r8   exc_type	exc_valueexc_tracebackstater   "is_progress_made_since_last_uplaods           r#   _should_retryRecoverableUpload._should_retry[  sC    ""8MM++I6N)7:L:L)L&))r&   c                 $    U R                  U5      $ rv   )rp   )r   r8   s     r#   _perform_upload!RecoverableUpload._perform_uploadg  s    ""9--r&   c                     U R                  5       n[        R                  " U R                  U5      n[        R
                  " U R                  UU/S9$ )N)targetshould_retry_iftarget_args)r   	functoolspartialr   storage_retry_utilretryerr   )r   r8   new_should_retrys      r#   rt   RecoverableUpload.runj  sM    '')I ((););YG%%##(K r&   )r   )NNNN)rw   rx   ry   rz   r{   r   r   r   r   rt   r~   r   r&   r#   r   r   2  s'    ?*" ?C.2
.r&   r   c                   B   ^  \ rS rSrSr   SU 4S jjrU 4S jrSrU =r$ )ResumableUploadiu  zDUploads objects with support for resuming between runs of a command.c                 L   > [         [        U ]  UUUUU5        XPl        Xpl        g rv   )superr   r$   _serialization_data_tracker_callback)	r   r   r   r   r    serialization_datar!   tracker_callback	__class__s	           r#   r$   ResumableUpload.__init__x  s1     
/4)  2-r&   c                   > U R                   b>  U R                   S   nU R                  U5      nX l        [        R                  " SU5        O[
        [        U ]  5       nU R                  b  U R                  SU05        U$ )zSets up the upload session and returns the upload id.

Additionally, it does the following tasks:
1. Grabs the persisted size on the backend.
2. Sets the appropiate write offset.
3. Calls the tracker callback.

Returns:
  The upload session ID.
r8   zWrite offset after resuming: %s)	r   r   r   r   debugr   r   r   r   )r   r8   r9   r   s      r#   r   "ResumableUpload._initialize_upload  sz     +**;7i++I6l'	ii1<@ACi)
k956r&   )r   r   r   )NNN)	rw   rx   ry   rz   r{   r$   r   r~   __classcell__r   s   @r#   r   r   u  s     L .( r&   r   c                   D   ^  \ rS rSrSr SU 4S jjrS rS rS rSr	U =r
$ )	StreamingUploadi  a  Uploads objects from a stream with support for error recovery in-flight.

Stream is split into chunks of size set by property upload_chunk_size,
rounded down to be a multiple of MAX_WRITE_CHUNK_BYTES.

For example if upload_chunk_size is 7 MiB and MAX_WRITE_CHUNK_BYTES is
2 MiB, it will be rounded down to 6 MiB. If upload_chunk_size is less than
MAX_WRITE_CHUNK_BYTES, it will be equal to MAX_WRITE_CHUNK_BYTES.
c                 l   > [         [        U ]  UUUUU5        SU l        U R	                  5       U l        g r/   )r   r   r$   _log_chunk_warning_get_chunk_sizer   )r   r   r   r   r    r!   r   s         r#   r$   StreamingUpload.__init__  s>     
/4) $D++-Dr&   c                    [         R                  " [        R                  R                  R
                  R                  5       5      nUU R                  R                  R                  R                  R                  :  aH  UU R                  R                  R                  R                  R                  -  nUS:  a  SU l        X-
  $ SU l        U R                  R                  R                  R                  R                  $ )a  Returns the chunk size corrected to be multiple of MAX_WRITE_CHUNK_BYTES.

It also sets the attribute _should_log_message if it is needed to log
the warning message.

Look at the docstring on StreamingUpload class.

Returns:
  (int) The chunksize value corrected.
r   T)r   ParseIntegerr   VALUESrm   upload_chunk_sizeGetr   r>   rA   rB   rC   r   )r   initial_chunk_sizeadjust_chunk_sizes      r#   r   StreamingUpload._get_chunk_size  s     (44!!33779; 	<<..55KK	L LL//66LLM  
Q	"&33"D<<..55KKKr&   c                 d   U R                   (       d  g [        R                  " [        R                  R
                  R                  R                  5       5      n[        R                  " SR                  [        R                  " U R                  5      [        R                  " U5      5      5        g )NzmData will be sent in chunks of {} instead of {}, as configured in the storage/upload_chunk_size config value.)r   r   r   r   r   rm   r   r   r   warningformatFormatBinaryNumberr   )r   r   s     r#   _log_messageStreamingUpload._log_message  s~    ""'44!!33779; KKL
&2243C3CD223EFH	r&   c                     U R                  5         S n U R                  U5      nU R                  (       a   U$ UR                  U l        M8  rv   )r   rp   r   r   r   )r   r8   responses      r#   r   StreamingUpload._perform_upload  sL    H
((3h		%	%O $22d	 r&   )r   r   r   rv   )rw   rx   ry   rz   r{   r$   r   r   r   r~   r   r   s   @r#   r   r     s'      .$L8 r&   r   )#r{   
__future__r   r   r   r|   rR   r   r1   googlecloudsdk.api_lib.storager   r   'googlecloudsdk.api_lib.storage.gcs_grpcr   r   "googlecloudsdk.command_lib.storager	   ,googlecloudsdk.command_lib.storage.resourcesr
   +googlecloudsdk.command_lib.storage.tasks.cpr   googlecloudsdk.corer   r   googlecloudsdk.core.utilr   sixwith_metaclassABCMetaobjectr   r   r   r   r   r   r&   r#   <module>r      s    - &  ' 
   	 K = A > 8 K A # * 3 
uc  f5 up7 &@ @F/' /dP' Pr&   