U
    8Yc?                     @   s  d dl Z d dlmZmZmZ d dlmZmZmZm	Z	 d dl
Z
d dlZd dlmZ d dlZd dlZd dlmZmZmZmZmZmZmZmZmZmZ d dlZd dlZd dlmZmZm Z m!Z!m"Z" d dl#m$Z$m%Z%m&Z&m'Z' d dl(Z(d dl)m*Z*m+Z+ d dl,Z-e(j.d	kZ/e0e1Z2d
Z3dd Z4dd Z5G dd deZ6dd Z7dd Z8d;ddZ9dd Z:dd Z;dd Z<d<ddZ=e= Z> Z?Z@d d! ZAd"d# ZBG d$d% d%eCZDe jEd&d' ZFd(d) ZGd=d+d,ZHd-d. ZId>d0d1ZJd2d3 ZKd4d5 ZLd?d7d8ZMd@d9d:ZNdS )A    N)ProcessPoolExecutorThreadPoolExecutorExecutor)ENOENTEACCESEPERMEROFS)chain)
isdirisfilebasenamedirnamejoinsplitlexistsnormpathabspathislink)S_IEXECS_IMODES_ISDIRS_ISREGS_IWRITE)check_outputCalledProcessErrorSTDOUTlist2cmdline)mkdtempNamedTemporaryFileZwin32z.c~c                 C   s   ddl m} || S )Nr   )find_executable)Zdistutils.spawnr   )
executabler    r!   ;lib/python3.8/site-packages/conda_package_handling/utils.pywhich   s    r#   c              
   C   s   zft | j}t|r0t | t|tB tB  n2t|s@t	| rVt | t|tB  nt
d|  W dS  tk
r } z`t|dd }|tfkrt
d|   n6|tttfkrt
d| | W Y dS t
d| |  W 5 d }~X Y nX d S )Nz path cannot be made writable: %sTerrnoz,tried to make writable, but didn't exist: %sz%tried make writable but failed: %s
%rFz!Error making path writable: %s
%r)oslstatst_moder   chmodr   r   r   r   r   logdebug	Exceptiongetattrr   r   r   r   warn)pathmodeeZenor!   r!   r"   make_writable   s$    

r1   c                   @   s   e Zd Zdd ZdS )DummyExecutorc                 g   s"   |D ]}|D ]}||V  qqd S Nr!   )selffunc	iterablesiterablethingr!   r!   r"   map5   s    zDummyExecutor.mapN)__name__
__module____qualname__r9   r!   r!   r!   r"   r2   4   s   r2   c                 C   s   | dkrt  S t| dS )N   Zmax_workers)r2   r   )Z	processesr!   r!   r"   get_executor;   s    r?   c                 C   sr   t | rTt| D ]>\}}}t||fD ]$} ztt||  W q*   Y q*X q*qnzt|  W n   Y nX d S r3   )r
   r%   walkr	   from_iterabler1   r   )r.   rootdirsfilesr!   r!   r"   recursive_make_writable?   s    rE   c                    s   |st rdnd}|dkr t| S g }| D ]R d kr:d}n.d krHd}n t fdddD sdd}nd}||  |  q(d	|S d S )
Ncmd.exeZbash"'c                 3   s   | ]}| kV  qd S r3   r!   ).0_argr!   r"   	<genexpr>c   s     z"quote_for_shell.<locals>.<genexpr>) 
 rN   )on_winr   anyappendr   )Z	argumentsshellZquotedZquoter!   rK   r"   quote_for_shellQ   s    rU   c                 O   s  t | } trHztd| dtd}W q   zd }tdddL}|dt| g |d |dt| g |d	 |j}W 5 Q R X t	|d
}|
 }| |kstW 5 Q R X tjd }d}	t|dd|gdd d d |	d}W nT tk
r> }
 z4|
jdkrtd|  ntd| W 5 d }
~
X Y nX Y nX nztd W n   Y nX td}|rtdrz.t|dddtt dd | d gtd}W n& tk
r   td| Y nX td t|  d S )NzRD /S /Q "{}" > NUL 2> NULT)rT   stderr.batF)suffixdeletez	RD /S {}
zchcp 65001
zEXIT 0
rZCOMSPECi   z/dz/c)rT   stdoutrV   stdinZcreationflags   z7Removing folder {} the fast way failed.  Output was: {}z:removing dir contents the fast way failed.  Output was: {}z.emptyrsyncz-az--forcez--delete/rV   )r   rQ   r   formatr   r   writerU   nameopenreadAssertionErrorr%   environr   
returncoder)   errorr*   makedirsr#   r
   r   getcwdshutilrmtree)r.   argskwargsoutrc   Z
batch_filecontentsZcontentZcomspecZCREATE_NO_WINDOWr0   r^   r!   r!   r"   rm   k   sh    



  
 

rm   c                 C   sN  zt |  t|  W n0 tk
rH   zt| | d  W n tk
rB   tr.tdd}t|d$}|d |d |d W 5 Q R X t	| \}}| d }d}t
|r|jd	 d
| }|d7 }qd}z tdd|||t|gtd}W n( tk
r"   td| | Y nX W 5 Q R X td|  Y nX Y nX dS )zIf files are in use, especially on windows, we can't remove them.
    The fallback path is to rename them (but keep their folder the same),
    which maintains the file handle validity.  See comments at:
    https://serverfault.com/a/503769
    z.conda_trashrW   )rX   wz@pushd "%1"
z@REM Rename src to destz@ren "%2" "%3" > NUL 2> NUL")r=   r   z.conda_trash_{}z	< empty >rF   z/Cr`   z6renaming file path {} to trash failed.  Output was: {}znCould not remove or rename {}.  Please remove this file manually (you may need to reboot to free file handles)N)r1   r%   unlinkEnvironmentErrorrenamerQ   r   rd   rb   r   r   splitextra   r   r   r   r   r)   r-   )r.   Ztrash_scriptfZ_dirnameZ_fnZdest_fnZcounterrp   r!   r!   r"   unlink_or_rename_to_trash   sD    



 rx   c                 C   s0   t | }t|r,t|s,t| t |}qd S r3   )r   r
   r%   listdirrmdir)r.   parent_pathr!   r!   r"   remove_empty_parent_paths   s    r|   Fc                 O   s   t |  dzDt| } t| r.t| s.t|  nt| r@t|  nt	d|  W 5 t| rltd|    dS X  t| rt
|  |rt|  dS )z
    Completely delete path
    max_retries is the number of times to retry on failure. The default is 5. This only applies
    to deleting a directory.
    If removing path fails and trash is True, files will be moved to the trash directory.
    zrm_rf failed for %sFNz0rm_rf failed. Not a link, file, or directory: %sT)rE   r   r)   infor   r
   r   rz   rx   r*   delete_trashr|   )r.   Zclean_empty_parentsrn   kwr!   r!   r"   rm_rf   s     

r   c                    s   | s
t j} tdg tj| ddD ]\}}} fdd|D |d d < |D ]z}t|dsjt|dt rJt||}zt| t	| W qJ t
tfk
r } ztd||j| W 5 d }~X Y qJX qJq"d S )	NZenvsTtopdownc                    s   g | ]}| kr|qS r!   r!   )rI   dZexcluder!   r"   
<listcomp>  s      z delete_trash.<locals>.<listcomp>z*.conda_trash**z%r errno %d
Cannot unlink %s.)sysprefixsetr%   r@   fnmatchCONDA_TEMP_EXTENSIONr   rs   r|   OSErrorIOErrorr)   r*   r$   )r   rB   rC   rD   fnfilenamer0   r!   r   r"   r~     s     
 

r~   c                 C   s\   t | sd S zt|  W n   Y nX tj| ddD ]"\}}}|D ]}tt|| qBq4d S )NFr   )r
   rm   r%   r@   rx   r   )dirpathrB   rC   rD   rw   r!   r!   r"   rz     s    rz   c                   @   sZ   e Zd ZdZdZdZdde fddZdd	 Z	d
d Z
defddZdd Zdd ZdS )TemporaryDirectorya+  Create and return a temporary directory.  This has the same
    behavior as mkdtemp but can be used as a context manager.  For
    example:

        with TemporaryDirectory() as tmpdir:
            ...

    Upon exiting the context, the directory and everything contained
    in it are removed.
    NFrP   z.cph_tmpc                 C   s   t |||| _d S r3   )r   rc   )r4   rX   r   dirr!   r!   r"   __init__2  s    zTemporaryDirectory.__init__c                 C   s   d | jj| jS )Nz	<{} {!r}>)ra   	__class__r:   rc   r4   r!   r!   r"   __repr__5  s    zTemporaryDirectory.__repr__c                 C   s   | j S r3   )rc   r   r!   r!   r"   	__enter__8  s    zTemporaryDirectory.__enter__c                 C   s`   | j r\| js\zt| j  W n   |d| j   Y nX d| _|r\|jr\|d| |j d S )NzConda-package-handling says: "I tried to clean up, but I could not.  There is a mess in %s that you might want to clean up yourself.  Sorry..."TzImplicitly cleaning up {!r})rc   _closedr   r-   ra   ResourceWarning)r4   _warn	_warningsr!   r!   r"   cleanup;  s    
zTemporaryDirectory.cleanupc                 C   s   |    d S r3   r   )r4   excvaluetbr!   r!   r"   __exit__H  s    zTemporaryDirectory.__exit__c                 C   s   | j dd d S )NT)r   r   r   r!   r!   r"   __del__K  s    zTemporaryDirectory.__del__)r:   r;   r<   __doc__rc   r   r%   rk   r   r   r   r   r   r   r   r!   r!   r!   r"   r   "  s   r   c              	   c   s.   t  }zt |  d V  W 5 t | X d S r3   )r%   rk   chdir)destcurdirr!   r!   r"   	tmp_chdirP  s
    

r   c                 C   s,   t | tst| ds(| d k	r$| g} ng } | S )N__iter__)
isinstancestrhasattrrK   r!   r!   r"   ensure_listZ  s
    r   z(.*[\\\\/])?\.git[\\\\/].*z(.*[\\\\/])?\.git$z(.*)?\.DS_Store.*z.*\.la$zconda-meta.*c                    s>   |D ]&}t |}t| tt|j|  } q fdd| D S )zIRemove things like the .git directory from the list of files to be copiedc                    s<   g | ]4}t jt j |s4t jt j |s|qS r!   )r%   r.   r   r   r
   )rI   rw   r   r!   r"   r   l  s    z filter_files.<locals>.<listcomp>)recompiler   filtermatch)
files_listr   filter_patternspatternrZ   r!   r   r"   filter_filesc  s    
r   c                 C   s   t | |ddS )N)zinfo[\\/]index.jsonzinfo[\\/]fileszinfo[\\/]paths.jsonzinfo[\\/]about.jsonzinfo[\\/]has_prefixzinfo[\\/]hash_input_fileszinfo[\\/]hash_input.jsonzinfo[\\/]run_exports.yamlzinfo[\\/]run_exports.jsonzinfo[\\/]gitzinfo[\\/]recipe[\\/].*zinfo[\\/]recipe_log.jsonzinfo[\\/]recipe.tarzinfo[\\/]test[\\/].*zinfo[\\/]LICENSE.txtzinfo[\\/]requireszinfo[\\/]metazinfo[\\/]platformzinfo[\\/]no_linkzinfo[\\/]link.jsonzinfo[\\/]icon.png)r   )r   )r   r   r!   r!   r"   filter_info_filess  s    r      c                    sP   t t|}|std|n| }t fdddD ]}|| q8| S )NzUnrecognized hash algorithm: {}c                      s
     S r3   )re   r!   
buffersizefdr!   r"   <lambda>      z_checksum.<locals>.<lambda>r   )r,   hashlib
ValueErrorra   iterupdateZ	hexdigest)r   	algorithmr   Z	hash_implblockr!   r   r"   	_checksum  s    
r   c                 C   s
   t | dS )NZsha256r   r   r!   r!   r"   sha256_checksum  s    r   c                 C   s
   t | dS )NZmd5r   r   r!   r!   r"   md5_checksum  s    r      c              
   C   s.   t | d}t|||W  5 Q R  S Q R X dS )zA
    Calculate a checksum for a filename (not an open file).
    rbN)rd   r   )r   r   r   r   r!   r!   r"   checksum  s    r   c              	      s>   t t|d fdd|D }W 5 Q R X dd |D S )zB
    Calculate multiple checksums for a filename in parallel.
    r>   c                    s   g | ]} t| qS r!   )Zsubmitr   )rI   r   r   r0   r   r!   r"   r     s     zchecksums.<locals>.<listcomp>c                 S   s   g | ]}|  qS r!   )result)rI   r   r!   r!   r"   r     s     )r   len)r   Z
algorithmsr   Zresultsr!   r   r"   	checksums  s     r   )N)F)r   )r   )r   )r   )O
contextlibZconcurrent.futuresr   r   r   r$   r   r   r   r   r   r   	itertoolsr	   Zloggingr%   os.pathr
   r   r   r   r   r   r   r   r   r   r   rl   statr   r   r   r   r   
subprocessr   r   r   r   r   Ztempfiler   r   warningsr   platformrQ   Z	getLogger__file__r)   r   r#   r1   r2   r?   rE   rU   rm   rx   r|   r   Ztry_rmdir_all_emptyZmove_to_trashZmove_path_to_trashr~   rz   objectr   contextmanagerr   r   r   r   r   r   r   r   r   r!   r!   r!   r"   <module>   sT   0


F)
.
		


