B
    âÖÓYQ[  ã               @   s‚  d Z ddlmZmZ ddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddl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 G d
d„ deƒZdd„ ZG dd„ deƒ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&d'„ Z*d(d)„ Z+d*d+„ Z,d,d-„ Z-d.d/„ Z.d0d1„ Z/G d2d3„ d3eƒZ0d6d4d5„Z1dS )7z!Bundle up a project for shipment.é    )Úabsolute_importÚprint_functionN)Ú_new_error_recorder)Úlogged_subprocess)ÚSimpleStatus)Ú"subdirectory_relative_to_directory)Úrename_over_existing)Úmakedirs_ok_if_existsc               @   s   e Zd Zdd„ ZdS )Ú	_FileInfoc             C   sb   t j |¡| _t jj| j|d| _t ¡ dkr@| j dd¡| _	n| j| _	t j 
| j¡| _
|| _d S )N)ÚstartZWindowsú\ú/)ÚosÚpathÚabspathÚ	full_pathÚrelpathÚrelative_pathÚplatformÚsystemÚreplaceÚunixified_relative_pathÚbasenameÚis_directory)ÚselfÚproject_directoryÚfilenamer   © r   ú8lib/python3.7/site-packages/anaconda_project/archiver.pyÚ__init__    s    z_FileInfo.__init__N)Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   r
      s   r
   c          
   C   sî   y°g }x¦t  | ¡D ]˜\}}}g }xD|D ]<}t| t j ||¡dd}	||	ƒrNq&q&| |¡ | |	¡ q&W ||d d …< x6|D ].}
t| t j ||
¡dd}	||	ƒsx| |	¡ qxW qW |S  tk
rè } z| d| t|ƒf ¡ d S d }~X Y nX d S )NT)r   r   r   FzCould not list files in %s: %s.)	r   Úwalkr
   r   ÚjoinÚappendÚOSErrorÚerrorÚstr)r   Zignore_filterÚfrontendZ
file_infosÚrootÚdirsÚfilesZfiltered_dirsÚdÚinfoÚfÚer   r   r   Ú_list_project+   s*    


r1   c               @   s   e Zd Zdd„ Zdd„ ZdS )Ú_FilePatternc             C   s   |dkst ‚|| _d S )NÚ )ÚAssertionErrorÚpattern)r   r5   r   r   r   r   J   s    z_FilePattern.__init__c             C   sf   dd„ }| j  d¡r| j }n
d| j  }d|j }| d¡rX|jrR|||d d… ƒS dS n
|||ƒS d S )Nc             S   s<   |   d¡st‚x(| dkr6t | |¡r(dS tj | ¡} qW dS )Nr   TF)Ú
startswithr4   Úfnmatchr   r   Údirname)r   r5   r   r   r   ÚmatchT   s    
z#_FilePattern.matches.<locals>.matchr   z*/éÿÿÿÿF)r5   r6   r   Úendswithr   )r   r.   r9   r5   Zmatch_againstr   r   r   ÚmatchesO   s    



z_FilePattern.matchesN)r    r!   r"   r   r<   r   r   r   r   r2   I   s   r2   c          
   C   sÈ   g }ynt  | dd¡V}xN|D ]F}| ¡ }| d¡r4q| d¡rJ|dd … }|dkr| t|d¡ qW W d Q R X |S  ttfk
rÂ } z.|jtj	kr˜|S | 
d| t|ƒf ¡ d S W d d }~X Y nX d S )	NÚrzutf-8ú#z\#é   r3   )r5   zFailed to read %s: %s)ÚcodecsÚopenÚstripr6   r%   r2   r&   ÚIOErrorÚerrnoZENOENTr'   r(   )r   r)   Úpatternsr/   Úliner0   r   r   r   Ú_parse_ignore_filer   s"    


rG   c             C   s   t j | d¡}t||ƒS )Nz.projectignore)r   r   r$   rG   )r   r)   Zignore_filer   r   r   Ú_load_ignore_file   s    rH   c          
   C   sÆ   t j t j | d¡¡sg S y.tjddddddg| d}dg| d	¡ ¡  S  tj	k
rŽ } z&|j
 d	¡ d
d¡}| d| ¡ d S d }~X Y n4 tk
rÀ } z| dt|ƒ ¡ d S d }~X Y nX d S )Nz.gitZgitzls-filesz--othersz	--ignoredz--exclude-standardz--directory)Úcwdzutf-8Ú
ú z0'git ls-files' failed to list ignored files: %s.z Failed to run 'git ls-files'; %s)r   r   Úexistsr$   r   Zcheck_outputÚdecodeÚ
splitlinesÚ
subprocessZCalledProcessErrorÚoutputr   r'   r&   r(   )r   r)   rP   r0   Úmessager   r   r   Ú_git_ignored_files•   s    rR   c                s.   t | |ƒ‰ ˆ d krd S tˆ ƒ‰ ‡ fdd„}|S )Nc                sH   | j }x<|dkrB|dkst‚|ˆ ks0|d ˆ kr4dS tj |¡}qW dS )Nr3   r   TF)r   r4   r   r   r8   )r.   r   )Úgit_ignoredr   r   Úis_git_ignoredº   s    
z#_git_filter.<locals>.is_git_ignored)rR   Úset)r   r)   rT   r   )rS   r   Ú_git_filter³   s    

rV   c                s&   t | |ƒ‰ ˆ d krd S ‡ fdd„}|S )Nc                s    xˆ D ]}|  | ¡rdS qW dS )NTF)r<   )r.   r5   )rE   r   r   Úmatches_some_patternÌ   s    

z1_ignore_file_filter.<locals>.matches_some_pattern)rH   )r   r)   rW   r   )rE   r   Ú_ignore_file_filterÇ   s
    
rX   c                sŽ   t | |ƒ‰ t| |ƒ‰ˆ d ks$ˆd kr(d S tƒ ‰x|D ]}ˆ |j¡‰q4W dd„ ˆD ƒ‰‡fdd„‰‡ ‡‡fdd„}t| ||ƒ}|d krŠd S |S )Nc             S   s   g | ]}t |ƒ‘qS r   )r2   )Ú.0Úsr   r   r   ú
<listcomp>Þ   s    z,_enumerate_archive_files.<locals>.<listcomp>c                s    xˆ D ]}|  | ¡rdS qW dS )NTF)r<   )r.   r5   )Úplugin_patternsr   r   Úis_plugin_generatedà   s    

z5_enumerate_archive_files.<locals>.is_plugin_generatedc                s   ˆ | ƒpˆ| ƒpˆ| ƒS )Nr   )r.   )Ú
git_filterÚignore_file_filterr]   r   r   Úall_filtersæ   s    z-_enumerate_archive_files.<locals>.all_filters)rV   rX   rU   ÚunionZignore_patternsr1   )r   r)   ÚrequirementsZreqr`   Úinfosr   )r^   r_   r]   r\   r   Ú_enumerate_archive_filesÕ   s    


rd   c             C   s‚   t ƒ }x| D ]}|||j< qW xN| D ]F}tj |j¡}x2|dkrh|dksLt‚||krZ||= tj |¡}q8W q$W t| ¡ dd„ dS )Nr3   r   c             S   s   | j S )N)r   )Úxr   r   r   Ú<lambda>ü   s    z_leaf_infos.<locals>.<lambda>)Úkey)Údictr   r   r   r8   r4   ÚsortedÚvalues)rc   Zall_by_namer.   Úparentr   r   r   Ú_leaf_infosð   s    


rl   c          	   C   sv   |d krd}nd| }t  |d| ¡F}x>t|ƒD ]2}tj | |j¡}| d| ¡ |j|j	|d q2W W d Q R X d S )Nr3   ú:zw%sz
  added %s)Úarcname)
ÚtarfilerA   rl   r   r   r$   r   r.   Úaddr   )Úarchive_root_namerc   r   Úcompressionr)   Útfr.   rn   r   r   r   Ú
_write_tarÿ   s    rt   c          	   C   s\   t  |d¡F}x>t|ƒD ]2}tj | |j¡}| d| ¡ |j|j	|d qW W d Q R X d S )NÚwz
  added %s)rn   )
ÚzipfileÚZipFilerl   r   r   r$   r   r.   Úwriter   )rq   rc   r   r)   Úzfr.   rn   r   r   r   Ú
_write_zip  s
    rz   c             C   s(   t | ||d}|d krd S dd„ |D ƒS )N)rb   c             S   s   g | ]
}|j ‘qS r   )r   )rY   r.   r   r   r   r[     s    zD_list_relative_paths_for_unignored_project_files.<locals>.<listcomp>)rd   )r   r)   rb   rc   r   r   r   Ú0_list_relative_paths_for_unignored_project_files  s    r{   c       
         sÎ  |   ¡ }|dk	r0x|jD ]}| j |¡ qW |S t| jƒ}tj | jj	¡sn| d| jj
 ¡ tdd| ¡ dS | jjrš| d| jj
 ¡ tdd| ¡ dS t| j|| jd}|dkrÆtdd| ¡ dS t|| jƒ‰ tj ˆ ¡sð‡ fd	d
„|D ƒ}|d tt ¡ ƒ }zyÂ| ¡  d¡r,t| j|||ƒ n’| ¡  d¡rRt| j||d|d nl| ¡  d¡rxt| j||d|d nF| ¡  d¡ržt| j||d|d n | d| ¡ tdd| ¡ dS t||ƒ W nD tk
r } z$| t|ƒ¡ tdd| | ¡ dS d}~X Y nX W dyt |¡ W n ttfk
r<   Y nX X g }x*| j  ¡ D ]}	|	j!j"rP| #|	j¡ qPW t$|ƒdkr¾| %d¡ | %d¡ t$|ƒt$| jƒkr¾| %dd &t'|ƒ¡ ¡ tdd| dS )zôMake an archive of the non-ignored files in the project.

    Args:
        project (``Project``): the project
        filename (str): name for the new zip or tar.gz archive file

    Returns:
        a ``Status``, if failed has ``errors``
    Nz%s does not exist.FzCan't create an archive.)ÚsuccessÚdescriptionÚerrorsz#%s has been modified but not saved.)rb   z$Failed to list files in the project.c                s   g | ]}|j ˆ kr|‘qS r   )r   )rY   r.   )Úrelative_dest_filer   r   r[   D  s    z$_archive_project.<locals>.<listcomp>z.tmp-z.zipz.tar.gzZgz)rr   r)   z.tar.bz2Úbz2z.tarz Unsupported archive filename %s.z>Project archive filename must be a .zip, .tar.gz, or .tar.bz2.z#Failed to write project archive %s.r   zjWarning: env specs are not locked, which means they may not work consistently for others or when deployed.zI  Consider using the 'anaconda-project lock' command to lock the project.z  Unlocked env specs are: z, TzCreated project archive %s)r|   r}   )(Zproblems_statusr~   r)   r'   r   r   r   rL   Zproject_filer   r   r   Ú
pop_errorsZhas_unsaved_changesrd   Zdirectory_pathZ"union_of_requirements_for_all_envsr   Úisabsr(   ÚuuidZuuid4Úlowerr;   rz   Únamert   r   rC   Úremover&   Z	env_specsrj   Zlock_setZdisabledr%   Úlenr.   r$   ri   )
Zprojectr   Zfailedr'   r)   rc   Ztmp_filenamer0   ZunlockedZenv_specr   )r   r   Ú_archive_project  sp    





rˆ   c          	   C   s&   t j| dd}t| ¡ ƒS Q R X d S )Nr=   )Úmode)rv   rw   ri   Znamelist)Úzip_pathry   r   r   r   Ú_list_files_zipp  s    r‹   c          	   C   s0   t j| dd}tdd„ | ¡ D ƒƒS Q R X d S )Nr=   )r‰   c             S   s"   g | ]}|  ¡ s| ¡ r|j‘qS r   )ÚisregÚisdirr…   )rY   Úmemberr   r   r   r[   x  s    z#_list_files_tar.<locals>.<listcomp>)ro   rA   ri   Z
getmembers)Útar_pathrs   r   r   r   Ú_list_files_taru  s    r   c             C   sÐ   t  ¡ }z˜tj| dd€}| |¡ xn|D ]f\}}| d||f ¡ tj ||¡}tj 	|¡rtt
|ƒ t ||¡ q*t
tj |¡ƒ t ||¡ q*W W d Q R X W d yt |¡ W n ttfk
rÈ   Y nX X d S )Nr=   )r‰   zUnpacking %s to %s)ÚtempfileZmkdtemprv   rw   Z
extractallr.   r   r   r$   r   r	   ÚshutilZcopystatr8   Zcopy2ÚrmtreerC   r&   )rŠ   Úsrc_and_destr)   Ztmpdirry   ÚsrcÚdestZsrc_pathr   r   r   Ú_extract_files_zip{  s     
r—   c          
   C   sÒ   t j| ddº}x²|D ]ª\}}| d||f ¡ | |¡}| ¡ r`ttj |¡ƒ | 	||¡ n| 
¡ slt‚t|ƒ y| ||d¡ W n  tk
r¦   | ||¡ Y nX | ||¡ | ||¡ qW W d Q R X d S )Nr=   )r‰   zUnpacking %s to %sF)ro   rA   r.   Z	getmemberrŒ   r	   r   r   r8   Zmakefiler   r4   ÚchownÚ	TypeErrorÚchmodÚutime)r   r”   r)   rs   r•   r–   rŽ   r   r   r   Ú_extract_files_tar“  s    
rœ   c                s$   |   dtj¡} ‡ fdd„‰ ˆ | d ƒS )Nr   c                sJ   t j | ¡\}}|dkr | |fS |d kr2ˆ ||ƒS ˆ |t j ||¡ƒS d S )Nr3   )r   r   Úsplitr$   )ÚheadÚtailr8   r   )Ú_helperr   r   r    ®  s    
z#_split_after_first.<locals>._helper)r   r   Úsep)r   r   )r    r   Ú_split_after_firstª  s    r¢   c          	   C   sÆ  || ƒ}t |ƒdkr"| d¡ d S dd„ t|dd„ |D ƒƒD ƒ}|d d }|dkrn| d|d d  ¡ d S |d krz|}tj |¡r´|d ks’t‚tj tj |¡¡}tj 	|¡}	nB|d krÄt 
¡ }tj tj |¡¡}	tj tj tj |	|¡¡¡}| |	¡st‚tj |¡r&| d	| ¡ d S g }
x’|D ]Š\}}}||krZ| d
||f ¡ d S |d krhq0tj tj tj ||¡¡¡}| |¡sª| d|||f ¡ d S |
 ||f¡ q0W ||
fS )Nr   z7A valid project archive must contain at least one file.c             S   s   g | ]\}\}}|||f‘qS r   r   )rY   r…   ÚprefixÚ	remainderr   r   r   r[   Ã  s   z._get_source_and_dest_files.<locals>.<listcomp>c             S   s   g | ]}t |ƒ‘qS r   )r¢   )rY   r…   r   r   r   r[   Ä  s    r?   z..z9Archive contains relative path '%s' which is not allowed.zDirectory '%s' already exists.zwA valid project archive contains only one project directory with all files inside that directory. '%s' is outside '%s'.z>Archive entry '%s' would end up at '%s' which is outside '%s'.)r‡   r'   Úzipr   r   r‚   r4   Úrealpathr   r8   Úgetcwdr$   r6   rL   r%   )Zarchive_pathÚ
list_filesÚproject_dirÚ
parent_dirr)   ÚnamesÚitemsZcandidate_prefixÚcanonical_project_dirZcanonical_parent_dirr”   r…   r£   r¤   r–   r   r   r   Ú_get_source_and_dest_files½  sN    


r®   c                   s   e Zd Z‡ fdd„Z‡  ZS )Ú_UnarchiveStatusc                s   t t| ƒj||d || _d S )N)r|   r}   )Úsuperr¯   r   r©   )r   r|   r}   r©   )Ú	__class__r   r   r   ø  s    z_UnarchiveStatus.__init__)r    r!   r"   r   Ú__classcell__r   r   )r±   r   r¯   ÷  s   r¯   c       
         sÒ  |dk	r$t j |¡r$|dk	r$tdƒ‚t|ƒ}d}d}ˆ  d¡rHt}t}nDt‡ fdd„dD ƒƒrht	}t
}n$| dˆ  ¡ tdd	ˆ  | ¡ d
S yôtˆ ||||ƒ}|dkr¼tdd	ˆ  | ¡ d
S |\}}t|ƒdkrð| d¡ tdd	ˆ  | ¡ d
S t j |¡rt‚t  |¡ y|ˆ ||ƒ W nR tk
rn }	 z2yt |¡ W n ttfk
rX   Y nX |	‚W dd}	~	X Y nX tdd| |dS  tttjtjfk
rÌ }	 z | t|	ƒ¡ tdd| ¡ d
S d}	~	X Y nX dS )aî  Unpack an archive of files in the project.

    This takes care of several details, for example it deals with
    hostile archives containing files outside of the dest
    directory, and it handles both tar and zip.

    It does not load or validate the unpacked project.

    project_dir can be None to auto-choose one.

    If parent_dir is non-None, place the project_dir in it. This is most useful
    if project_dir is None.

    Args:
        archive_filename (str): the tar or zip archive file
        project_dir (str): the directory that will contain the project config file
        parent_dir (str): place project directory in here

    Returns:
        a ``Status``, if failed has ``errors``, on success has a ``project_dir`` property
    NzJIf supplying parent_dir to unarchive, project_dir must be relative or Nonez.zipc                s   g | ]}ˆ   |¡‘qS r   )r;   )rY   Úsuffix)Úarchive_filenamer   r   r[     s    z&_unarchive_project.<locals>.<listcomp>)z.tarz.tar.gzz.tar.bz2zEUnsupported archive filename %s, must be a .zip, .tar.gz, or .tar.bz2FzCould not unpack archive %s)r|   r}   r~   r   z9Archive does not contain a project directory or is empty.TzProject archive unpacked to %s.)r|   r}   r©   zFailed to read project archive.)r   r   r‚   Ú
ValueErrorr   r;   r‹   r—   Úanyr   rœ   r'   r   r   r®   r‡   rL   r4   ÚmakedirsÚ	Exceptionr’   r“   rC   r&   r¯   rv   ro   ZTarErrorr(   )
r´   r©   r)   rª   r¨   Zextract_filesÚresultr­   r”   r0   r   )r´   r   Ú_unarchive_projectþ  sV    


rº   )N)2Ú__doc__Z
__future__r   r   r@   rD   r7   r   r   r’   rO   ro   r‘   rƒ   rv   Zanaconda_project.frontendr   Zanaconda_project.internalr   Z'anaconda_project.internal.simple_statusr   Z,anaconda_project.internal.directory_containsr   Z anaconda_project.internal.renamer   Z"anaconda_project.internal.makedirsr	   Úobjectr
   r1   r2   rG   rH   rR   rV   rX   rd   rl   rt   rz   r{   rˆ   r‹   r   r—   rœ   r¢   r®   r¯   rº   r   r   r   r   Ú<module>   sP   )	T: