
                         p    d Z ddlmZ ddlmZ ddlmZ ddlZddlmZ ddlmZ ddl	m
Z
 d	Z G d
 d      Zy)z.Utilities for representing a part of a stream.    )absolute_import)division)unicode_literalsN)errors)	hash_util)
installersi   c                   ~    e Zd ZdZ	 	 	 ddZd Zd ZddZd Zd Z	d	 Z
dd
Zej                  fdZddZd Zd Zy)UploadStreamzImplements a subset of the io.IOBase API, adding functionality for uploads.

  When data is read from a stream, this class
  1. Updates hash digesters.
  2. Executes a progress callbacks if a byte threshold is passed.
  Nc                     || _         || _        ||ni | _        || _        d| _        d| _        d| _        d| _        d| _        y)a  Initializes a FilePart instance.

    Args:
      stream (io.IOBase): The underlying stream wrapped by this class.
      length (int|None): The total number of bytes in the UploadStream.
      digesters (dict[util.HashAlgorithm, hashlib hash object]|None): Values are
        updated with with data as it's read.
      progress_callback (func[int]|None): Accepts an amount of processed bytes
        and submits progress information for aggregation.
    Nr   F)	_stream_length
_digesters_progress_callback(_bytes_read_since_last_progress_callback_progress_updated_with_end_byte_checkpoint_digesters_checkpoint_absolute_index_start_byte)selfstreamlength	digestersprogress_callbacks        7lib/googlecloudsdk/command_lib/storage/upload_stream.py__init__zUploadStream.__init__&   sP     DLDL#,#8ibDO/D45D1+0D(!%D&'D#D    c                 6    | j                   j                         S )aN  Returns absolute position in the stream.

    Hashing and progress reporting logic relies on absolute positions. Since
    child classes overwrite `tell` to make it return relative positions, we need
    to write hashing and progress reporting in a way that does not reference
    `self.tell`, which this function makes possible.
    )r   tellr   s    r   _get_absolute_positionz#UploadStream._get_absolute_positionA   s     <<r   c                 8    | j                   j                  |      S )a  Seeks to a position in the underlying stream.

    Catching up digesters sometimes requires seeking to a specific position in
    self._stream. Child classes wrap streams which are not seekable, and have
    different strategies to make it appear that a seek has occured, which can
    be supported by overriding this method.

    Args:
      offset (int): the position to seek to.

    Returns:
      the new position in the stream.
    )r   seek)r   offsets     r   _update_absolute_positionz&UploadStream._update_absolute_positionK   s     <<V$$r   c                 8    | j                   j                  |      S )a\  Reads bytes from the underlying stream.

    Child classes do not always read directly from the stream. Progress
    reporting and hashing logic can be reused by overriding only this method.

    Args:
      size (int): the number of bytes to read. If less than 0, all bytes are
          returned.

    Returns:
      bytes from self._stream.
    )r   read)r   sizes     r   	_get_datazUploadStream._get_data[   s     <<T""r   c                     | j                   sy| j                         | _        t        j                  | j                         | _        y)zEUpdates checkpoint that holds old hashes to optimize backwards seeks.N)r   r    r   r   copy_digestersr   r   s    r   _save_digesters_checkpointz'UploadStream._save_digesters_checkpointj   s4    ??&*&A&A&CD#!*!9!9$//!JDr   c                    | j                   sy|| j                  k  r;| j                  | j                         t	        j
                  | j                          n|| j                         k  re| j                  | j                         | j                   j                  | j                         t	        j                  | j                        | _        n|| j                         k(  ry| j                          	 | j                  t        || j                         z
  t        j                              }|syt	        j                  | j                   |       ^)z6Digests data between last and current stream position.N)r   r   r$   r   r   reset_digestersr    updater   r*   r+   r(   minr   WRITE_BUFFER_SIZEupdate_digesters)r   new_absolute_indexdatas      r   _catch_up_digestersz UploadStream._catch_up_digestersq   s   ??D;;;
$$T%5%560	d99;	;
$$T%D%DE ooT778#,#;#;

$
$$&d 	t::<	< 	##%
^^
 4#>#>#@@**,-d   $7 r   c                 "    | j                         S )z+Returns the current position in the stream.)r    r   s    r   r   zUploadStream.tell   s    &&((r   c                    | j                          | j                  |      }|rt        j                  | j                  |       | j
                  ry| xj                  t        |      z  c_        | j                  t        k\  rHd| _        | j                  | j                                | j                         | j                  k(  | _        |S )z0Returns `size` bytes from the underlying stream.r   )r+   r(   r   r1   r   r   r   len_PROGRESS_CALLBACK_THRESHOLDr    r   r   r   )r   r'   r3   s      r   r&   zUploadStream.read   s    ##%>>$D  $7		 	 55TB599():;$
7

!
!$"="="?
@151L$
.Kr   c                     |t         j                  k(  r1| j                  r|| j                  z   }n>t        j                  d      |t         j
                  k(  r| j                         |z   }n|}| j                  |       | j                  |      S )aI  Goes to a specific point in the stream.

    Args:
      offset (int): The number of bytes to move.
      whence: Specifies the position offset is added to.
        os.SEEK_SET: offset is added to the current byte.
        os.SEEK_END, os.SEEK_CUR are not supported.

    Returns:
      The new position in the stream (int).
    zASEEK_END is not supported if the length of the stream is unknown.)	osSEEK_ENDr   r   ErrorSEEK_CURr    r4   r$   )r   r#   whencer2   s       r   r"   zUploadStream.seek   s     	#dll2llOQ 	Q	2;;	6686A!/0))*<==r   c                     | j                   r4| j                  s(|s| j                  | j                                d| _        | j                  j	                         S )zCloses the underlying stream.T)r   r   r    r   close)r   caught_errors     r   r@   zUploadStream.close   sH    (L(L ; ; =>-1d*<<r   c                     | S )N r   s    r   	__enter__zUploadStream.__enter__   s    Kr   c                 :    | j                  t        |             y )N)rA   )r@   bool)r   
error_typeunused_argss      r   __exit__zUploadStream.__exit__   s    JJD,J-r   )NNN))F)__name__
__module____qualname____doc__r   r    r$   r(   r+   r4   r   r&   r:   SEEK_SETr"   r@   rD   rI   rC   r   r   r
   r
      sY     !%	6% #K 8D)  !# >6 .r   r
   )rN   
__future__r   r   r   r:   "googlecloudsdk.command_lib.storager   r   googlecloudsdk.core.updaterr   r8   r
   rC   r   r   <module>rS      s1    5 &  ' 	 5 8 2' p. p.r   