U
    þ¯b*  ã                   @   s  d dl Z d dlZd dlmZ d dlmZ d dlmZmZ d dl	m
Z
 d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZmZmZmZ z,d dlmZ d dlmZmZ d dlmZ W n e k
rØ   edƒ‚Y nX dZ!G dd„ de
ƒZ"eG dd„ deƒƒZ#dS )é    N)Ú	timedelta)ÚSpooledTemporaryFile)ÚImproperlyConfiguredÚSuspiciousOperation)ÚFile)Útimezone)Údeconstructible)Úforce_bytes)ÚBaseStorage)Úcheck_locationÚ
clean_nameÚget_available_overwrite_nameÚ	safe_joinÚsetting)ÚNotFound)ÚBlobÚClient)Ú_quotezfCould not load Google Cloud Storage bindings.
See https://github.com/GoogleCloudPlatform/gcloud-pythonÚcontent_typec                       s`   e Zd Zdd„ Zedd„ ƒZdd„ Zdd„ ZeeeƒZd‡ fd
d„	Z	‡ fdd„Z
dd„ Z‡  ZS )ÚGoogleCloudFilec                 C   sd   || _ t |¡d | _|| _|| _|j |¡| _| jsTd|krTt	| j |j|j
d�| _d | _d| _d S )Nr   Úw)Ú
chunk_sizeF)ÚnameÚ	mimetypesÚ
guess_typeÚ	mime_typeÚ_modeÚ_storageÚbucketÚget_blobÚblobr   Úblob_chunk_sizeÚ_fileÚ	_is_dirty)Úselfr   ÚmodeZstorage© r&   ú</tmp/pip-unpacked-wheel-_urp_i0d/storages/backends/gcloud.pyÚ__init__   s     þzGoogleCloudFile.__init__c                 C   s   | j jS ©N)r    Úsize©r$   r&   r&   r'   r*   ,   s    zGoogleCloudFile.sizec                 C   sR   | j d krLt| jjdtdƒd�| _ d| jkrLd| _| j | j ¡ | j  	d¡ | j S )Nz.GSStorageFileZFILE_UPLOAD_TEMP_DIR)Úmax_sizeÚsuffixÚdirÚrFr   )
r"   r   r   Úmax_memory_sizer   r   r#   r    Zdownload_to_fileÚseekr+   r&   r&   r'   Ú	_get_file0   s    
ý
zGoogleCloudFile._get_filec                 C   s
   || _ d S r)   )r"   )r$   Úvaluer&   r&   r'   Ú	_set_file=   s    zGoogleCloudFile._set_fileNc                    s*   d| j krtdƒ‚|d krd}tƒ  |¡S )Nr/   z!File was not opened in read mode.éÿÿÿÿ)r   ÚAttributeErrorÚsuperÚread)r$   Ú	num_bytes©Ú	__class__r&   r'   r8   B   s
    
zGoogleCloudFile.readc                    s(   d| j krtdƒ‚d| _tƒ  t|ƒ¡S )Nr   z"File was not opened in write mode.T)r   r6   r#   r7   Úwriter	   )r$   Úcontentr:   r&   r'   r<   K   s    
zGoogleCloudFile.writec                 C   sV   | j d k	rR| jrB| j | j¡}| jj| jd| j| 	d| jj
¡d� | j  ¡  d | _ d S )NTÚacl)Úrewindr   Úpredefined_acl)r"   r#   r   Úget_object_parametersr   r    Úupload_from_fileÚfiler   ÚgetÚdefault_aclÚclose)r$   Úblob_paramsr&   r&   r'   rF   Q   s    
  þ
zGoogleCloudFile.close)N)Ú__name__Ú
__module__Ú__qualname__r(   Úpropertyr*   r2   r4   rC   r8   r<   rF   Ú__classcell__r&   r&   r:   r'   r      s   

	r   c                       s´   e Zd Z‡ fdd„Zdd„ Zedd„ ƒZedd„ ƒZd	d
„ Zd'dd„Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd d!„ Zd"d#„ Zd(‡ fd%d&„	Z‡  ZS ))ÚGoogleCloudStoragec                    s&   t ƒ jf |Ž t| ƒ d | _d | _d S r)   )r7   r(   r   Ú_bucketÚ_client)r$   Úsettingsr:   r&   r'   r(   ^   s    zGoogleCloudStorage.__init__c                 C   sh   t dƒt dƒt dƒt dd ƒt ddƒt dƒt dd	ƒt d
tdd�ƒt dd	ƒt dƒt di ƒt ddƒt dƒdœS )NZGS_PROJECT_IDZGS_CREDENTIALSZGS_BUCKET_NAMEZGS_CUSTOM_ENDPOINTZGS_LOCATIONÚ ZGS_DEFAULT_ACLZGS_QUERYSTRING_AUTHTZGS_EXPIRATIONi€Q )ÚsecondsZGS_FILE_OVERWRITEZGS_CACHE_CONTROLZGS_OBJECT_PARAMETERSZGS_MAX_MEMORY_SIZEr   ZGS_BLOB_CHUNK_SIZE)Ú
project_idÚcredentialsÚbucket_nameÚcustom_endpointÚlocationrE   Úquerystring_authÚ
expirationÚfile_overwriteÚcache_controlÚobject_parametersr0   r!   )r   r   r+   r&   r&   r'   Úget_default_settingsf   s    ðz'GoogleCloudStorage.get_default_settingsc                 C   s"   | j d krt| j| jd�| _ | j S )N)ÚprojectrT   )rO   r   rS   rT   r+   r&   r&   r'   Úclientz   s    
þzGoogleCloudStorage.clientc                 C   s    | j d kr| j | j¡| _ | j S r)   )rN   r_   r   rU   r+   r&   r&   r'   r   ƒ   s    
zGoogleCloudStorage.bucketc                 C   s4   zt | j|ƒW S  tk
r.   td| ƒ‚Y nX dS )aA  
        Normalizes the name so that paths like /path/to/ignored/../something.txt
        and ./file.txt work.  Note that clean_name adds ./ to some paths so
        they need to be fixed here. We check to make sure that the path pointed
        to is not outside the directory specified by the LOCATION setting.
        z Attempted access to '%s' denied.N)r   rW   Ú
ValueErrorr   ©r$   r   r&   r&   r'   Ú_normalize_name‰   s    ÿz"GoogleCloudStorage._normalize_nameÚrbc                 C   s0   |   t|ƒ¡}t||| ƒ}|js,td| ƒ‚|S )NzFile does not exist: %s)rb   r   r   r    ÚFileNotFoundError)r$   r   r%   Úfile_objectr&   r&   r'   Ú_open–   s
    zGoogleCloudStorage._openc           	      C   s–   t |ƒ}|  |¡}||_t|d| ƒ}i }|  |¡}| d| j¡|d< t|krV|j|t< | 	¡ D ]\}}t
|j||ƒ q^|jj|fd|jdœ|—Ž |S )NÚrwr>   r@   T)r?   r*   )r   rb   r   r   rA   ÚpoprE   ÚCONTENT_TYPEr   ÚitemsÚsetattrr    rB   r*   )	r$   r   r=   Zcleaned_namere   Zupload_paramsrG   ÚpropÚvalr&   r&   r'   Ú_save�   s    


zGoogleCloudStorage._savec                 C   s2   | j  ¡ }d|kr.| jr.t dt¡ | j|d< |S )z­Override this to return a dictionary of overwritable blob-property to value.

        Returns GS_OBJECT_PARAMETRS by default. See the docs for all possible options.
        r[   z¾The GS_CACHE_CONTROL setting is deprecated. Use GS_OBJECT_PARAMETERS to set any writable blob property or override GoogleCloudStorage.get_object_parameters to vary the parameters per object.)r\   Úcopyr[   ÚwarningsÚwarnÚDeprecationWarning)r$   r   r\   r&   r&   r'   rA   ±   s    
ý
z(GoogleCloudStorage.get_object_parametersc                 C   s8   |   t|ƒ¡}z| j |¡ W n tk
r2   Y nX d S r)   )rb   r   r   Zdelete_blobr   ra   r&   r&   r'   ÚdeleteÂ   s
    zGoogleCloudStorage.deletec                 C   sN   |s0z| j  | j¡ W dS  tk
r.   Y dS X |  t|ƒ¡}t| j |¡ƒS )NTF)r_   Z
get_bucketr   r   rb   r   Úboolr   ra   r&   r&   r'   ÚexistsÉ   s    zGoogleCloudStorage.existsc           
      C   sœ   |   t|ƒ¡}|r$| d¡s$|d7 }| jj|dd�}t|ƒ}|j}g }g }|D ]}|j d¡}| 	|d ¡ qN|D ]}	|	 d¡}| 	|d ¡ qrt|ƒ|fS )Nú/)ÚprefixÚ	delimiterr5   éþÿÿÿ)
rb   r   Úendswithr   Z
list_blobsÚlistÚprefixesr   ÚsplitÚappend)
r$   r   ÚiteratorZblobsr|   ÚfilesÚdirsr    ÚpartsZfolder_pathr&   r&   r'   ÚlistdirÔ   s    
zGoogleCloudStorage.listdirc                 C   s&   | j  |¡}|d kr"td |¡ƒ‚|S )NzFile does not exist: {})r   r   r   Úformat©r$   r   r    r&   r&   r'   Ú	_get_blobë   s    zGoogleCloudStorage._get_blobc                 C   s   |   t|ƒ¡}|  |¡}|jS r)   )rb   r   r†   r*   r…   r&   r&   r'   r*   ô   s    
zGoogleCloudStorage.sizec                 C   s$   |   t|ƒ¡}|  |¡}t |j¡S r)   )rb   r   r†   r   Ú
make_naiveÚupdatedr…   r&   r&   r'   Úmodified_timeù   s    
z GoogleCloudStorage.modified_timec                 C   s4   |   t|ƒ¡}|  |¡}|j}tdƒr*|S t |¡S )NÚUSE_TZ)rb   r   r†   rˆ   r   r   r‡   )r$   r   r    rˆ   r&   r&   r'   Úget_modified_timeþ   s    
z$GoogleCloudStorage.get_modified_timec                 C   s4   |   t|ƒ¡}|  |¡}|j}tdƒr*|S t |¡S )z•
        Return the creation time (as a datetime) of the file specified by name.
        The datetime will be timezone-aware if USE_TZ=True.
        rŠ   )rb   r   r†   Ztime_createdr   r   r‡   )r$   r   r    Úcreatedr&   r&   r'   Úget_created_time  s    
z#GoogleCloudStorage.get_created_timec                 C   s˜   |   t|ƒ¡}| j |¡}|  |¡}| d| j¡dkp<| j }| jsN|rN|j	S |rjdj
| jt|dd�d�S | js€|j| jdd�S |j| j| jdd	�S d
S )z«
        Return public url or a signed url for the Blob.
        This DOES NOT check for existance of Blob - that makes codes too slow
        for many use cases.
        r>   Z
publicReadz {storage_base_url}/{quoted_name}s   /~)Úsafe)Zstorage_base_urlZquoted_nameZv4)rY   Úversion)Zbucket_bound_hostnamerY   r�   N)rb   r   r   r    rA   rD   rE   rX   rV   Z
public_urlr„   r   Zgenerate_signed_urlrY   )r$   r   r    rG   Zno_signed_urlr&   r&   r'   Úurl  s,    
ÿ

þ ÿýzGoogleCloudStorage.urlNc                    s&   t |ƒ}| jrt||ƒS tƒ  ||¡S r)   )r   rZ   r   r7   Úget_available_name)r$   r   Ú
max_lengthr:   r&   r'   r‘   ,  s    
z%GoogleCloudStorage.get_available_name)rc   )N)rH   rI   rJ   r(   r]   rK   r_   r   rb   rf   rn   rA   rs   ru   rƒ   r†   r*   r‰   r‹   r�   r�   r‘   rL   r&   r&   r:   r'   rM   \   s(   


	
rM   )$r   rp   Údatetimer   Útempfiler   Zdjango.core.exceptionsr   r   Zdjango.core.files.baser   Zdjango.utilsr   Zdjango.utils.deconstructr   Zdjango.utils.encodingr	   Zstorages.baser
   Zstorages.utilsr   r   r   r   r   Zgoogle.cloud.exceptionsr   Zgoogle.cloud.storager   r   Zgoogle.cloud.storage.blobr   ÚImportErrorri   r   rM   r&   r&   r&   r'   Ú<module>   s(   >