B
    XM\Óo  ã               @   sÒ  d dl mZmZmZ d dl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 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 ddlmZ d dlmZ d d	lmZmZ d d
lm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ e$rd dlm,Z, ej-d  dkr d dl.m/Z/ nd dl0m/Z/ e 1d¡Z2e 1d¡Z3dd„ Z4d4dd„Z5dd„ Z6d5dd„Z7d6dd„Z8d7dd„Z9d8d d!„Z:d"d#„ Z;d9d$d%„Z<d&d'„ Z=d(d)„ Z>d*d+„ Z?d,d-„ Z@d.d/„ ZAd:d0d1„ZBd2d3„ ZCdS );é    )Úabsolute_importÚdivisionÚprint_functionN)ÚjoinÚisdirÚisfileÚabspathÚbasenameÚexistsÚnormpathÚ
expanduser)ÚCalledProcessErroré   )ÚdownloadÚTemporaryDirectory)Úhashsum_file)Úexternal)Úurl_pathÚCondaHTTPError)Údecompressible_extsÚtar_xfÚsafe_print_unicodeÚ	copy_intoÚon_winÚensure_listÚcheck_output_envÚcheck_call_envÚ convert_path_for_cygwin_or_msys2Ú
get_loggerÚrm_rfÚLoggingContext)Úconvert_unix_path_to_winé   )Úurljoinz(?:.+)\.(.+)\.(?:.+)\s(.+)z(.*?)(\.(?:tar\.)?[^.]+)$c             C   s   t  d |d d… ¡| ¡S )Nz\1_{}\2é
   )Úext_reÚsubÚformat)ÚfnZ
hash_value© r)   ú1lib/python3.7/site-packages/conda_build/source.pyÚappend_hash_to_fn#   s    r+   Fc             C   sà  t tƒ}|r| d|  ¡ t| ƒs,t | ¡ |d }t|tƒsD|g}d|krT|d n
t|d ƒ }}d}x8dD ] }	|	|krnt	|||	 ƒ}d}P qnW | 
d |¡¡ t| |ƒ}
t|
ƒrÊ|rÆ| d	| ¡ nv|rÜ| d
| ¡ x`|D ]B}d|kr6| d¡rt|ƒ}tj |¡s,tj tj ||¡¡}t|ƒ}n(| d¡r^dt|dd… ƒ dd¡ }y4|rt| d| ¡ tƒ  t||
ƒ W dQ R X W n‚ tk
rÔ } z"| 
dt|ƒ ¡  ¡ t|
ƒ W dd}~X Y qä tk
r } z"| 
dt|ƒ ¡  ¡ t|
ƒ W dd}~X Y qäX |r&| d¡ P qäW t|
ƒ td| ƒ‚d}xTdD ]L}||krJ|| }t|
|ƒ}||kr’t|
ƒ td| ¡ ||f ƒ‚P qJW |sØ|s°t|
dƒ}t	|
|ƒ}tj |¡sÔt |
|¡ |}
|
|fS )z' Download a source to the local cache. zSource cache directory is: %sÚurlr(   r   F)Zmd5Zsha1Úsha256TznNo hash (md5, sha1, sha256) provided for {}.  Source download forced.  Add hash to recipe to use source cache.zFound source in cache: %szDownloading source to cache: %sz://ú~z	file:///~zfile:///é   Nú\ú/zDownloading %sz	Error: %sZSuccesszCould not download %sz%s mismatch: '%s' != '%s'r-   ) r   Ú__name__Úinfor   ÚosÚmakedirsÚ
isinstanceÚlistr	   r+   Úwarnr'   r   r   Ú
startswithr   ÚpathÚisabsr   r   Úreplacer    r   r   ÚstrÚstripr   ÚRuntimeErrorr   ÚupperÚshutilÚmove)Úcache_folderÚrecipe_pathÚsource_dictÚverboseÚlogZsource_urlsÚunhashed_fnr(   Z
hash_addedZ	hash_typer:   r,   ÚeZhashedÚtpZexpected_hashZ	dest_pathr)   r)   r*   Údownload_to_cache'   s„    

 










rK   c          	   C   s   t j | ¡}t  | ¡}tƒ j}x,|D ]$}t t j | |¡t j ||¡¡ q$W t| ƒ x,|D ]$}t t j ||¡t j ||¡¡ qZW W dQ R X dS )z¬Moves all files/folders one level up.

    This is for when your archive extracts into its own folder, so that we don't need to
    know exactly what that folder is called.N)	r4   r:   ÚdirnameÚlistdirr   rA   rB   r   r   )Znested_folderÚparentÚflistÚtmpdirÚentryr)   r)   r*   Úhoist_single_extracted_foldery   s    

$
rR   é„  Tc          	   C   s  t ||| |ƒ\}}	t|ƒs$t |¡ |r0tdƒ t|dØ}
tj |
|	¡}| ¡  	t
¡rdt||
ƒ ntdƒ t||||d | ¡  	d¡ršt||||d t |
¡}tj |
|d ¡}t|ƒdkrÖtj |¡rÖt|ƒ t |
¡}x,|D ]$}t tj |
|¡tj ||¡¡ qæW W dQ R X dS )	z! Uncompress a downloaded source. zExtracting download)ÚdirzNWarning: Unrecognized source format. Source file will be copied to the SRC_DIR)Úlockingz.whlr   r   N)rK   r   r4   r5   Úprintr   r:   r   ÚlowerÚendswithr   r   r   rM   ÚlenrR   rA   rB   )rE   Úsrc_dirrC   rD   ÚcrootrF   ÚtimeoutrU   Zsrc_pathrH   rP   Zunhashed_destrO   ÚfolderÚfr)   r)   r*   Úunpackˆ   s(    



r_   éÿÿÿÿc	             C   sŠ  |rd}	d}
nt tjdƒ}|}	|}
| |tj ¡sDt d||f ¡ t| |ƒ d¡}t| |ƒ d¡}|pjd}| d¡}t	tj
 |¡ƒs˜t tj
 |¡¡ t	|ƒr,yR|dkrÂt| dg||	|
d n0t| ddd	g||	|
d t| d
ddg||	|
d W n4 tk
r(   d |¡}t|ƒ t |¡ ‚ Y nX n°| ddg}|dkrP|dt|ƒg7 }yt|||g |	|
d W nb tk
rÌ   tjdkrœ| d¡rœt|ƒ}tj
 |¡r²t|ƒ}t|||g |	|
d Y nX t	|ƒsÜt‚t| d||g|	|
d |rT|}| d¡r&t| d|g|	|
d}| d¡}|r8td| ƒ |rTt| d|g||	|
d y,t| dddddg|	|d}| d¡ ¡ }W n tk
rš   g }Y nX x®|D ]¦}t |¡}|r¢| d¡d dkr¢| d¡}| d¡}t|d |ƒ}tj
 tj
  ||¡¡}|rtd |||f ƒ t!ƒ  }t"| ||||||d!|d"	 W dQ R X q¢W |rxt| d#d$d%d&g||	|
d t#||d' |s†| $¡  dS )(az   Mirror (and checkout) a Git repository recursively.

        It's not possible to use `git submodule` on a bare
        repository, so the checkout must be done before we
        know which submodules there are.

        Worse, submodules can be identified by using either
        absolute URLs or relative paths.  If relative paths
        are used those need to be relocated upon mirroring,
        but you could end up with `../../../../blah` and in
        that case conda-build could be tricked into writing
        to the root of the drive and overwriting the system
        folders unless steps are taken to prevent that.
    NÚwzBError: Attempting to mirror to %s which is outside of GIT_CACHE %sr1   ÚHEADZfetch)ÚcwdÚstdoutÚstderrÚoriginz+HEAD:_conda_cache_origin_headzsymbolic-refz#refs/heads/_conda_cache_origin_headzAFailed to update local git cache. Deleting local cached repo: {} Úclonez--mirrorr   z--depth)rd   re   Úwin32Ú.z	rev-parsezutf-8zcheckout: %rÚcheckoutÚconfigz--filez.gitmodulesz--get-regexpr,   )re   rc   é   r   z?Relative submodule %s found: url is %s, submod_mirror_dir is %sF)Ú	git_cacheÚgit_refÚ	git_depthÚis_top_levelrF   Ú	submoduleÚupdatez--initz--recursive)rF   )%Úopenr4   Údevnullr9   ÚsepÚsysÚexitr   Úrstripr   r:   rL   r5   r   r   r'   rV   rA   Zrmtreer=   Úplatformr!   r
   r   ÚAssertionErrorr   ÚdecodeÚ
splitlinesÚgit_submod_reÚmatchÚgroupr#   r   r   Úgit_mirror_checkout_recursiveÚgit_infoÚclose)ÚgitÚ
mirror_dirZcheckout_dirÚgit_urlrm   rn   ro   rp   rF   rd   re   ÚFNULLZgit_mirror_dirZgit_checkout_dirÚmsgÚargsrj   ÚoutputZ
submodulesrq   ZmatchesZsubmod_nameZsubmod_rel_pathZ
submod_urlZsubmod_mirror_dirZtemp_checkout_dirr)   r)   r*   r€   §   s     














r€   c             C   s  t |ƒst |¡ t d¡}|s*t d¡ t|  dd¡ƒ}|  d¡pFd}| d }| 	d¡rftj
 |¡}| 	d	¡r¬tttj
 ||¡ƒƒ}tjd
krž| dd¡}	qè|dd… }	n<| d¡d  dtj¡}	|	 	tj¡rÜ|	dd… }	|	 dd¡}	t||	ƒ}
t||
|||||d|d	 |S )z? Download a source from a Git repo (or submodule, recursively) rƒ   zOError: git is not installed in your root environment or as a build requirement.ro   r`   Zgit_revrb   r…   r.   ri   rh   ú:Ú_r   Nz://r1   T)rm   rn   ro   rp   rF   )r   r4   r5   r   Úfind_executablerv   rw   ÚintÚgetr9   r:   r   r   r   r   ry   r<   Úsplitru   r€   )rE   rm   rZ   rD   rF   rƒ   ro   rn   r…   Zgit_dnr„   r)   r)   r*   Ú
git_source*  s0    






r   c             C   sT  t | ƒst‚t d¡}|s0ttƒ}| d¡ dS |r:d}nttj	dƒ}|}tj
 ¡ }t| dƒ|d< dd„ | ¡ D ƒ}xÚd	D ]Ò\}}	yt| ¡ || |d
}
W n6 tk
rÐ } z|	rÀtdt|ƒ ƒ‚W dd}~X Y nX t ¡ }|sætjj}|pìd}t|
dƒr|
 |d¡}
|r0| d| ¡ |rL| |
d ¡ qz|rztd| ƒ t|
d ƒ qzW dS )z Print info about a Git repo. rƒ   zGgit not installed in root environment.  Skipping recording of git info.Nra   z.gitZGIT_DIRc             S   s   i | ]\}}t |ƒt |ƒ“qS r)   )r=   )Ú.0ÚkeyÚvaluer)   r)   r*   ú
<dictcomp>`  s    zgit_info.<locals>.<dictcomp>))zgit log -n1T)zgit describe --tags --dirtyF)z
git statusT)re   rc   Úenvzgit error: %szutf-8r{   Úignorez==> %s <==
Ú
)r   rz   r   rŒ   r   r2   r8   rs   r4   rt   ÚenvironÚcopyr   Úitemsr   r   r   Ú	Exceptionr=   ÚlocaleZgetpreferredencodingrv   rd   ÚencodingÚhasattrr{   ÚwriterV   r   )rZ   rF   Zforƒ   rG   re   r†   r•   ÚcmdZcheck_errorrd   rI   r   r)   r)   r*   r   L  s@    


"r   c             C   sø   |rd}d}nt tjdƒ}|}|}| d }t|ƒs<t |¡ | d¡d  dd¡}t||ƒ}	t|	ƒrztdd	g|	||d
 n"tdd||	g||d t|	ƒsœt	‚|  
d¡p¨d}
|rºtd|
 ƒ tdd|	|g||d tddd|
g|||d
 |sô| ¡  |S )z( Download a source from Mercurial repo. Nra   Úhg_urlrŠ   r`   r1   r‹   ÚhgZpull)rc   rd   re   rg   )rd   re   Zhg_tagZtipzcheckout: %rrr   z-C)rs   r4   rt   r   r5   r   r<   r   r   rz   rŽ   rV   r‚   )rE   rZ   Úhg_cacherF   rd   re   r†   r¡   Zhg_dnÚ
cache_reporr   r)   r)   r*   Ú	hg_sourcez  s2    

r¥   c             C   s  |rd}d}nt tjdƒ}|}|}dd„ }	| d }
|  d¡p>d}|	|  d¡pNd	ƒ}t|ƒsdt |¡ |
 d
d¡d  dd¡ d
d¡}t||ƒ}|ršdg}ng }t|ƒrÄt	ddd|g| |||d n.t	ddd|g| |
|g ||d t|ƒsòt
‚t|||d|d |s| ¡  |S )z" Download a source from SVN repo. Nra   c             S   s   t | ƒ ¡  ¡ dkS )N)ZyesÚtrueÚ1Zon)r=   rW   r>   )Úsr)   r)   r*   Ú
parse_bool©  s    zsvn_source.<locals>.parse_boolÚsvn_urlZsvn_revÚheadÚsvn_ignore_externalsZnorŠ   r   r`   r1   r‹   z--ignore-externalsÚsvnZupz-r)rc   rd   re   Úco)rd   re   T)ÚsymlinksrU   )rs   r4   rt   rŽ   r   r5   r   r<   r   r   rz   r   r‚   )rE   rZ   Ú	svn_cacherF   r\   rU   rd   re   r†   r©   rª   Zsvn_revisionr¬   Zsvn_dnr¤   Z
extra_argsr)   r)   r*   Ú
svn_sourceŸ  s6    
 

r±   c             C   sX  yt t| dƒƒrDtddddg| d}tdddg| d}d	 ||¡S tt| d
ƒƒrˆtdddg| d}tddg| d ¡ d }d	 ||¡S tt| dƒƒrìtddg| d}| d¡}tjd|tj	d 
d¡}tjd|tj	d 
d¡}d ||¡S d | t tj t| dƒ¡¡¡S W nD tk
rR   ttƒ d|  ¡ d | t tj t| dƒ¡¡¡S X dS )zThis tries to get information about where a recipe came from.  This is different
    from the source - you can have a recipe in svn that gets source via git.z.gitrƒ   rk   z--getzremote.origin.url)rc   z	rev-parserb   zOrigin {}, commit {}z.hgr¢   ÚpathsÚdefaultÚidr   z.svnr­   r3   zutf-8zRepository Root: (.*)$)Úflagsr   zRevision: (.*)$z{}, Revision {}z{}, last modified {}z	meta.yamlzFailed to checkout source in N)r
   r   r   r'   r   r   r{   ÚreÚsearchÚMr   ÚtimeZctimer4   r:   Úgetmtimer   r   r2   Údebug)rD   rf   Zrevr3   ZserverZrevisionr)   r)   r*   Úget_repository_infoÈ  s0    


r¼   c          
   C   sX   | d }t | dƒ<}t |dƒ&}x|D ]}| | dd¡¡ q&W W dQ R X W dQ R X |S )zFReplace windows line endings with Unix.  Return path to modified file.Z_unixÚrbÚwbs   
ó   
N)rs   rŸ   r<   )r:   Úout_pathÚ	inputfileÚ
outputfileÚliner)   r)   r*   Ú_ensure_unix_line_endingsæ  s    
*rÄ   c          
   C   sX   | d }t | dƒ<}t |dƒ&}x|D ]}| | dd¡¡ q&W W dQ R X W dQ R X |S )zBReplace unix line endings with win.  Return path to modified file.Z_winr½   r¾   r¿   s   
N)rs   rŸ   r<   )r:   rÀ   rÁ   rÂ   rÃ   r)   r)   r*   Ú_ensure_win_line_endingsð  s    
*rÅ   c       	   	      s.  d}dd„ | D ƒ}|j dd}x,|D ]$}| d¡}|dkr>|nt||ƒ}q$W |dkrZd}nÐtƒ ‰ dd	„ t|d
 ƒD ƒ‰ xd|D ]\}| d¡}xLt|d
 ƒD ]<}tj t	|f|t
|ƒ | d… žŽ ¡r˜ˆ |  d
7  < q˜W q|W tˆ ˆ jdd‰ˆ ˆd  ˆ ˆd
  krtdƒ t‡ ‡fdd„ˆ  ¡ D ƒƒ}|S )z0 Determine the patch strip level automatically. Nc             S   s   h | ]}|j d d’qS )r–   )Úerrors)Úencode)r‘   Zfilestrr)   r)   r*   ú	<setcomp>ý  s    z+_guess_patch_strip_level.<locals>.<setcomp>r–   )rÆ   ó   /r   c             S   s   i | ]
}d |“qS )r   r)   )r‘   Úir)   r)   r*   r”     s    z,_guess_patch_strip_level.<locals>.<dictcomp>r   T)r’   Úreversez+Patch level ambiguous, selecting least deepc                s$   g | ]\}}|ˆ ˆd   kr|‘qS )r   r)   )r‘   r’   r“   )ÚhistoÚorderr)   r*   ú
<listcomp>  s    z,_guess_patch_strip_level.<locals>.<listcomp>)rÇ   ÚcountÚminÚdictÚranger   r4   r:   r
   r   rY   ÚsortedrŽ   rV   rš   )	ZfilesstrrZ   ÚmaxlevelÚfilesÚfileZnumslashZ
patchlevelÚpartsÚlevelr)   )rÌ   rÍ   r*   Ú_guess_patch_strip_levelú  s*    



(rÙ   c          	   C   s²   t  d¡}tƒ }tj| dd†}g }d}d}xr| ¡ D ]f}|rNt  d|¡sNd}d}| |¡}|r€| d¡dkr€| 	| d¡¡ q6|r6| 
d	¡r6| 
d
¡s6d}q6W W d Q R X ||fS )Nz^(?:---|\+\+\+) ([^\n\t]+)r–   )rÆ   TzFrom [0-9a-f]{40}Fr   z	/dev/nullrƒ   z
git --diff)r¶   ÚcompileÚsetÚiors   Ú	readlinesr~   r·   r   Úappendr9   )r:   Zre_filesrÕ   r^   Z
first_lineÚis_git_formatÚlÚmr)   r)   r*   Ú_get_patch_file_details  s     

râ   c             C   s.  t |ƒst d| ¡ |jr&d }d }nttjdƒ}|}|}t|ƒ\}}|r|rtj}	d|	d< d|	d< t	|dd|g| |||	d	 | j
d
7  _
nš|jr¢td| ƒ t d|j¡}
|
d krÐt dtj tj¡ ¡ t|| ƒ}d| dd|g}y6ttƒ}|jr| d¡ t	|
g| | ||d W n tk
r(   tjdkr"t|ƒ}||d< z¶y,|jrd| d¡ t	|
g| | ||d W n„   |jr–| d¡ | dd¡ t|ƒ}||d< z.yt	|
g| | ||d W n   ‚ Y nX W d tj |¡rút |¡ X Y nX W d tj |¡rt |¡ X n‚ Y nX d S )NzError: no such patch: %sra   zconda-buildZGIT_COMMITTER_NAMEzconda@conda-build.orgZGIT_COMMITTER_EMAILZamz--committer-date-is-author-date)rc   rd   re   r•   r   zApplying patch: %rÚpatchzì        Error:
            Cannot use 'git' (not a git repo and/or patch) and did not find 'patch' in: %s
            You can install 'patch' using apt-get, yum (Linux), Xcode (MacOSX),
            or conda, m2-patch (Windows),
        z-p%dz--ignore-whitespacez-izTrying to apply patch as-is)rc   rd   re   rh   r`   zQApplying unmodified patch failed.  Convert to unix line endings and trying again.zYApplying unix patch failed.  Convert to CRLF line endings and trying again with --binary.r   z--binary)r   rv   rw   rF   rs   r4   rt   râ   r˜   r   Zgit_commits_since_tagrV   r   rŒ   Zbuild_prefixÚpathsepr   Z	dir_pathsrÙ   r   r2   r3   r   ry   rÄ   ÚinsertrÅ   r:   r
   Úremove)rZ   r:   rk   rƒ   rd   re   r†   rÕ   rß   Zgit_envrã   Zpatch_strip_levelZ
patch_argsrG   Zunix_ending_fileZwin_ending_filer)   r)   r*   Úapply_patch'  sh    



rç   c       
         s.  |   d¡}tj | jj¡s(t | jj¡ d}t|dƒr>|g}n|}y°x¨|D ]ž‰ ˆ  d¡}|rttj 	| jj
|¡n| jj
}t‡ fdd„dD ƒƒrÂtˆ || jj| j| jj| jj| jj| jjd nôd	ˆ krètˆ | jj|| j| jjd
}nÎdˆ krtˆ || jj| jjd
 nªdˆ kr<tˆ || jj| jj| jj| jjd nzdˆ kr¢tj ˆ d ¡}ttt	| j|ƒƒƒ}| jjr„td||f ƒ t||| jjd| jjdd nt|ƒs¶t |¡ tˆ  dg ¡ƒ}x&|D ]}	t|t	| j|	ƒ| j|ƒ qÌW qNW W n0 tk
r$   t  !| jj
| jj
d ¡ ‚ Y nX | jj
S )zk
    given a recipe_dir:
      - download (if necessary)
      - unpack
      - apply patches (if any)
    ÚsourceNÚkeysr]   c             3   s   | ]}|ˆ kV  qd S )Nr)   )r‘   Úk)rE   r)   r*   ú	<genexpr>Š  s    zprovide.<locals>.<genexpr>)r(   r,   )rD   r[   rF   r\   rU   r…   )rF   r¡   rª   )rF   r\   rU   r:   zCopying %s to %sT)r¯   rU   ZclobberÚpatchesZ_failed_provide)"Zget_sectionr4   r:   r   rk   Zbuild_folderr5   rž   rŽ   r   Zwork_dirÚanyr_   Z	src_cacher[   rF   r\   rU   r   rm   r¥   r£   r±   r°   r   r   r   rV   r   r   rç   r   rA   rB   )
ZmetadataÚmetarƒ   Zdictsr]   rZ   Úsource_pathr:   rì   rã   r)   )rE   r*   Úprovidet  sT    









&rð   )F)FrS   T)Nr`   TT)NT)TN)TrS   T)N)DZ
__future__r   r   r   rÜ   rœ   r4   Úos.pathr   r   r   r   r	   r
   r   r   r¶   rA   Ú
subprocessr   rv   r¹   Zconda_interfacer   r   r   Zconda_build.os_utilsr   Zconda_build.conda_interfacer   r   Zconda_build.utilsr   r   r   r   r   r   r   r   r   r   r   r    r!   Úversion_infoZurllib.parser#   ZurlparserÚ   r}   r%   r+   rK   rR   r_   r€   r   r   r¥   r±   r¼   rÄ   rÅ   rÙ   râ   rç   rð   r)   r)   r)   r*   Ú<module>   sP   (8


R 
 
 
"
.%
)


M