B
    ðG®[ëq  ã               @   sœ   d 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m	Z	 ddl
mZmZmZ ddlmZmZmZmZmZ dZG dd„ deƒZG d	d
„ d
eƒZdS )až  The checks module contains two classes that are used to verify
conda packages and recipes: CondaPackageCheck and CondaRecipeCheck.

Each class contains specific checks that relate to validating packages
and recipes. These checks start with the letter 'C', which is an
abbreviation for 'conda'.

Checks C1101 through C1145 are housed in CondaPackageCheck.
Checks C2101 through C2126 are housed in CondaRecipeCheck.
é    N)ÚErrorÚPackageError)ÚFIELDSÚLICENSE_FAMILIESÚCONDA_FORGE_COMMENTS)Ú	all_asciiÚget_bad_seqÚget_object_typeÚensure_listÚ	fullmatchz:^(?:[><=]{0,2}(?:(?:[\d\*]+[!\._]?){1,})[+\w\*]*[|,]?){1,}c                   sL  e Zd ZdZ‡ fdd„Ze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d$d%„ Zd&d'„ Zd(d)„ Zed*d+„ ƒZd,d-„ Zed.d/„ ƒZd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Z d8d9„ Z!d:d;„ Z"d<d=„ Z#d>d?„ Z$d@dA„ Z%dBdC„ Z&dDdE„ Z'dFdG„ Z(dHdI„ Z)dJdK„ Z*‡  Z+S )LÚCondaPackageCheckz:Create checks in order to validate conda package tarballs.c                sî   t t| ƒ ¡  || _t | j¡| _|  | j¡| _| j 	dd¡\| _
| _| _tdd„ | j ¡ D ƒƒ| _| j d¡ ¡ | _t | j d¡¡| _| j d¡ ¡ | _| j d¡ ¡ | _t| jd	 d
kƒ| _t d¡| _t dtj¡| _t d¡| _ dS )zAInitialize conda package information for use with package checks.ú-é   c             s   s   | ]}|j V  qd S )N)Úpath)Ú.0Úmember© r   ú2lib/python3.7/site-packages/conda_verify/checks.pyú	<genexpr>%   s    z-CondaPackageCheck.__init__.<locals>.<genexpr>zinfo/index.jsonzutf-8z
info/fileszinfo/paths.jsonÚplatformÚwinz[a-z0-9_][a-z0-9_\-\.]*$z[gh][0-9a-f]{5,}z[\w\.]+$N)!Úsuperr   Ú__init__r   ÚtarfileÚopenÚarchiveÚretrieve_package_nameZdistÚrsplitÚnameÚversionÚbuildÚsetÚ
getmembersÚpathsÚextractfileÚreadÚindexÚjsonÚloadsÚdecodeÚinfoÚ
files_fileÚ
paths_fileÚboolÚwin_pkgÚreÚcompileÚname_patÚIÚhash_patÚversion_pat)Úselfr   )Ú	__class__r   r   r      s    zCondaPackageCheck.__init__c             C   sp   t j | ¡} t| ƒ}|r&td |¡ƒ‚|  d¡r<| dd… S |  d¡rR| dd… S td t j | ¡d ¡ƒ‚dS )	z6Retrieve the package name from the conda package path.z9Found invalid sequence "{}" in package in info/index.jsonz.tar.bz2Niøÿÿÿz.taréüÿÿÿz)Found package with invalid extension "{}"é   )Úosr   Úbasenamer   r   ÚformatÚendswithÚsplitext)r   Úseqr   r   r   r   /   s    

z'CondaPackageCheck.retrieve_package_namec             C   sl   | j  d¡}|dkr"t| jddƒS | j |¡r8| d¡rFt| jddƒS || jkrht| jdd	 || j¡ƒS dS )
z2Check the package name located in info/index.json.r   NZC1101z'Missing package name in info/index.json)Ú.r   Ú_ZC1103z-Found invalid package name in info/index.jsonZC1102zGFound package name in info/index.json "{}" does not match filename "{}")	r*   Úgetr   r   r1   Úmatchr<   r   r;   )r5   Úpackage_namer   r   r   Úcheck_package_name>   s    
z$CondaPackageCheck.check_package_namec             C   s   t | j d¡ƒ}|dkr&t| jddƒS | d¡s:| d¡rHt| jddƒS | j |¡r\t	|ƒrjt| jdd	ƒS || j
krŒt| jd
d || j
¡ƒS dS )z5Check the package version located in info/index.json.r   ÚNoneZC1104z*Missing package version in info/index.json)r@   r?   ZC1107zFPackage version in info/index.json cannot start or end with '_' or '.'ZC1105z/Found invalid version number in info/index.jsonZC1106zRFound package version in info/index.json "{}" does not match filename version "{}"N)Ústrr*   rA   r   r   Ú
startswithr<   r4   rB   r   r   r;   )r5   Úpackage_versionr   r   r   Úcheck_package_versionJ   s    
z'CondaPackageCheck.check_package_versionc             C   sZ   | j  d¡}|dk	rVy"t|ƒ}|dk r4t| jddƒS W n tk
rT   t| jddƒS X dS )z2Check the build number located in info/index.json.Úbuild_numberNr   ZC1109z<Build number in info/index.json cannot be a negative integerZC1108z2Build number in info/index.json must be an integer)r*   rA   Úintr   r   Ú
ValueError)r5   rJ   r   r   r   Úcheck_build_numberV   s    z$CondaPackageCheck.check_build_numberc             C   sR   | j  d¡}| j |¡s,t| jdd |¡ƒS || jkrNt| jdd || j¡ƒS dS )z*Check the build string in info/index.json.r    ZC1110z2Found invalid build string "{}" in info/index.jsonZC1111zWFound build number in info/index.json "{}" does not match build number "{}" in filenameN)r*   rA   r4   rB   r   r   r;   r    )r5   Zbuild_stringr   r   r   Úcheck_build_stringb   s
    
z$CondaPackageCheck.check_build_stringc             C   s&   | j  d¡}|dkr"t| jddƒS dS )z@Check that the dependencies field is present in info/index.json.ÚdependsNZC1112z*Missing "depends" field in info/index.json)r*   rA   r   r   )r5   rO   r   r   r   Úcheck_index_dependenciesj   s    z*CondaPackageCheck.check_index_dependenciesc             C   sˆ   t | j d¡ƒ}|dgkr„xh|D ]`}| ¡ }t|ƒdkrFt| jddƒS t|ƒdkr`tt|d ƒrlt|ƒdkr t| jd	d
 	|¡ƒS q W dS )zFCheck that the dependencies in info/index.json are properly formatted.rO   Nr   ZC1113z+Found empty dependencies in info/index.jsonr   r8   é   ZC1114z0Found invalid dependency "{}" in info/index.json)
r
   r*   rA   ÚsplitÚlenr   r   r   Úver_spec_patr;   )r5   ZdependenciesZ
dependencyZdependency_partsr   r   r   Úcheck_index_dependencies_specsp   s    

z0CondaPackageCheck.check_index_dependencies_specsc             C   s6   | j  d| j  d¡¡}|tkr2t| jdd |¡ƒS dS )z:Check that the license family in info/index.json is valid.Úlicense_familyÚlicenseZC1115z-Found invalid license "{}" in info/index.jsonN)r*   rA   r   r   r   r;   )r5   rW   r   r   r   Úcheck_license_family|   s    z&CondaPackageCheck.check_license_familyc             C   s    t | j| jƒst| jddƒS dS )z@Check that contents of info/index.json are all ascii characters.ZC1116z1Found non-ascii characters inside info/index.jsonN)r   r&   r.   r   r   )r5   r   r   r   Úcheck_index_encoding‚   s    z&CondaPackageCheck.check_index_encodingc             C   s*   t | j ¡ ƒt | jƒkr&t| jddƒS dS )z7Check for duplicate members inside the package tarball.ZC1117z*Found duplicate members inside tar archiveN)rS   r   r"   r#   r   r   )r5   r   r   r   Úcheck_duplicate_members‡   s    z)CondaPackageCheck.check_duplicate_membersc             C   sT   xN| j  ¡ D ]@}tjjdkr*|j d¡}n|j d¡}t|ƒst	| jddƒS qW dS )z7Check the tar archive members for non ascii characters.r   zutf-8ZC1118z:Found archive member names containing non-ascii charactersN)
r   r"   ÚsysÚversion_infoÚmajorr   r)   Úencoder   r   )r5   r   Zunicode_pathr   r   r   Úcheck_membersŒ   s    zCondaPackageCheck.check_membersc             C   s    t | j| jƒst| jddƒS dS )z3Check the info/files file for non ascii characters.ZC1119z=Found filenames in info/files containing non-ascii charactersN)r   r+   r.   r   r   )r5   r   r   r   Úcheck_files_file_encoding—   s    z+CondaPackageCheck.check_files_file_encodingc             C   sD   dd„ | j  d¡ ¡ D ƒ}x$|D ]}| d¡r t| jddƒS q W dS )zZCheck that the info/files file does not contain any files found within the info directory.c             S   s   g | ]}|  ¡ ‘qS r   )Ústrip)r   r   r   r   r   ú
<listcomp>ž   s    z?CondaPackageCheck.check_files_file_for_info.<locals>.<listcomp>zutf-8r*   ZC1120z4Found filenames in info/files that start with "info"N)r+   r)   Ú
splitlinesrG   r   r   )r5   Ú	filenamesÚfilenamer   r   r   Úcheck_files_file_for_infoœ   s    

z+CondaPackageCheck.check_files_file_for_infoc             C   s@   dd„ | j  d¡ ¡ D ƒ}t|ƒtt|ƒƒkr<t| jddƒS dS )z)Check the info/files file for duplicates.c             S   s   g | ]}|  ¡ ‘qS r   )ra   )r   r   r   r   r   rb   ¥   s    zECondaPackageCheck.check_files_file_for_duplicates.<locals>.<listcomp>zutf-8ZC1121z'Found duplicate filenames in info/filesN)r+   r)   rc   rS   r!   r   r   )r5   rd   r   r   r   Úcheck_files_file_for_duplicates£   s    z1CondaPackageCheck.check_files_file_for_duplicatesc             C   sŠ   dd„ | j  ¡ D ƒ}dd„ | j d¡ ¡ D ƒ}xVtt|ƒ t|ƒ¡ƒD ]<}||krft| j	dd 
|¡ƒS ||krFt| j	dd 
|¡ƒS qFW d	S )
zRCheck that the files listed in info/files exist in the tar archive and vice versa.c             S   s&   g | ]}|  ¡ s|j d ¡s|j‘qS )r*   )Úisdirr   rG   )r   r   r   r   r   rb   «   s    zCCondaPackageCheck.check_files_file_for_validity.<locals>.<listcomp>c             S   s"   g | ]}|  ¡  d ¡s|  ¡ ‘qS )r*   )ra   rG   )r   r   r   r   r   rb   ­   s    zutf-8ZC1122z9Found filename in info/files missing from tar archive: {}ZC1123z9Found filename in tar archive missing from info/files: {}N)r   r"   r+   r)   rc   Úsortedr!   Úunionr   r   r;   )r5   Úmembersrd   re   r   r   r   Úcheck_files_file_for_validity©   s    z/CondaPackageCheck.check_files_file_for_validityc             C   s6   x0| j  ¡ D ]"}| ¡ rt| jdd |j¡ƒS qW dS )z$Check the tar archive for hardlinks.ZC1124z Found hardlink {} in tar archiveN)r   r"   Zislnkr   r   r;   )r5   r   r   r   r   Úcheck_for_hardlinks·   s    z%CondaPackageCheck.check_for_hardlinksc             C   sH   dddddh}x4| j D ]*}||ks,| d¡rt| jdd |¡ƒS qW d	S )
z0Check the tar archive for unallowed directories.z
conda-metaz	conda-bldZpkgsZpkgs32Zenvs)z	.DS_Storeú~ZC1125z'Found unallowed file in tar archive: {}N)r#   r<   r   r   r;   )r5   Zunallowed_directoriesÚfilepathr   r   r   Úcheck_for_unallowed_files½   s    z+CondaPackageCheck.check_for_unallowed_filesc             C   sP   xJ| j D ]@}d|ksd|kr| jd dkrd| jkrt| jdd |¡ƒS qW dS )	z;Check that noarch Python packages contain the proper files.zinfo/package_metadata.jsonzinfo/link.jsonZsubdirZnoarchZpreferred_envZC1126z0Found {} however package is not a noarch packageN)r#   r*   r   r   r;   )r5   ro   r   r   r   Úcheck_for_noarch_infoÅ   s    z'CondaPackageCheck.check_for_noarch_infoc             C   sR   dd„ | j D ƒ}dd„ | j D ƒ}t|ƒ |¡}t|ƒdkrNt| jdd |¡ƒS dS )zDCheck that both .bat and .exe files don't exist in the same package.c             S   s"   g | ]}|  d ¡r|dd… ‘qS )z.batNr7   )r<   )r   ro   r   r   r   rb   Î   s    z;CondaPackageCheck.check_for_bat_and_exe.<locals>.<listcomp>c             S   s"   g | ]}|  d ¡r|dd… ‘qS )z.exeNr7   )r<   )r   ro   r   r   r   rb   Ï   s    r   ZC1127zDFound both .bat and .exe files with same basename in same folder: {}N)r#   r!   ÚintersectionrS   r   r   r;   )r5   Z	bat_filesZ	exe_filesZisectr   r   r   Úcheck_for_bat_and_exeÌ   s    z'CondaPackageCheck.check_for_bat_and_exec             C   s8   d}x.| j  ¡ D ] }|jdkr| j  |j¡ ¡ }qW |S )zŠExtract the has_prefix file from the archive and return it.

        If the file does not exist in the archive, None is returned.
        Nzinfo/has_prefix)r   r"   r   r$   r%   )r5   Úprefix_filer   r   r   r   rt   ×   s
    
zCondaPackageCheck.prefix_filec             C   s*   | j dk	r&t| j | jƒs&t| jddƒS dS )z5Check the info/has_prefix file for proper formatting.NZC1128z-Found non-ascii characters in info/has_prefix)rt   r   r.   r   r   )r5   r   r   r   Úcheck_prefix_fileã   s    
z#CondaPackageCheck.check_prefix_filec          	   C   s„   | j dk	r€xt| j  d¡ ¡ D ]`}| ¡ }y&| ¡ \}}}| d¡}| d¡}W n$ tk
rr   dd|  }}}Y nX |||fS W dS )z‡Extract the contents of the has_prefix file and return them.

        If the has_prefix file does not exist, None is returned.
        Nzutf-8z'"z/<dummy>/<placeholder>Útext)rt   r)   rc   ra   rR   rL   )r5   ÚlineÚplaceholderÚmodere   r   r   r   Úprefix_file_contentsé   s    

z&CondaPackageCheck.prefix_file_contentsc             C   s8   | j dk	r4| j \}}}|| jkr4t| jdd |¡ƒS dS )z<Check that the filenames in has_prefix exist in the archive.NZC1129z>Found filename "{}" in info/has_prefix not included in archive)rz   r#   r   r   r;   )r5   r@   re   r   r   r   Úcheck_prefix_file_filenameü   s    

z,CondaPackageCheck.check_prefix_file_filenamec             C   s6   | j dk	r2| j \}}}|dkr2t| jdd |¡ƒS dS )z8Check that the has_prefix mode is either binary or text.N)Úbinaryrv   ZC1130z*Found invalid mode "{}" in info/has_prefix)rz   r   r   r;   )r5   r@   ry   r   r   r   Úcheck_prefix_file_mode  s    
z(CondaPackageCheck.check_prefix_file_modec             C   sn   | j dk	rj| j \}}}|dkrj| jdkr6t| jddƒS | jrJt| jddƒS t|ƒdkrjt| jd	d
 |¡ƒS dS )z6Check that the has_prefix file binary mode is correct.Nr|   ÚpythonZC1131zLBinary placeholder found in info/has_prefix not allowed when building PythonZC1132zJBinary placeholder found in info/has_prefix not allowed in Windows packageéÿ   ZC1133zTBinary placeholder "{}" found in info/has_prefix does not have a length of 255 bytes)rz   r   r   r   r.   rS   r;   )r5   rx   ry   r@   r   r   r   Úcheck_prefix_file_binary_mode  s    

z/CondaPackageCheck.check_prefix_file_binary_modec             C   s2   x,| j D ]"}| d¡rt| jdd |¡ƒS qW dS )z2Check the tar archive for pre and post link files.)z-post-link.shz-pre-link.shz-pre-unlink.shz-post-link.batz-pre-link.batz-pre-unlink.batZC1134z(Found pre/post link file "{}" in archiveN)r#   r<   r   r   r;   )r5   ro   r   r   r   Úcheck_for_post_links  s    
z&CondaPackageCheck.check_for_post_linksc             C   s2   x,| j D ]"}| d¡rt| jdd |¡ƒS qW dS )z$Check the tar archive for egg files.z.eggZC1135zFound egg file "{}" in archiveN)r#   r<   r   r   r;   )r5   ro   r   r   r   Úcheck_for_egg  s    
zCondaPackageCheck.check_for_eggc             C   s2   x,| j D ]"}| d¡rt| jdd |¡ƒS qW dS )z/Check the tar archive for easy_install scripts.)zbin/easy_installzScripts/easy_installZC1136z)Found easy_install script "{}" in archiveN)r#   rG   r   r   r;   )r5   ro   r   r   r   Úcheck_for_easy_install_script%  s    
z/CondaPackageCheck.check_for_easy_install_scriptc             C   s2   x,| j D ]"}| d¡rt| jdd |¡ƒS qW dS )z%Check the tar archive for .pth files.z.pthZC1137z$Found namespace file "{}" in archiveN)r#   r<   r   r   r;   )r5   ro   r   r   r   Úcheck_for_pth_file+  s    
z$CondaPackageCheck.check_for_pth_filec             C   s<   x6| j D ],}| d¡r| jdkrt| jdd |¡ƒS qW dS )z$Check the tar archive for .pyo filesz.pyor~   ZC1138zFound pyo file "{}" in archiveN)r#   r<   r   r   r   r;   )r5   ro   r   r   r   Úcheck_for_pyo_file1  s    z$CondaPackageCheck.check_for_pyo_filec             C   sB   x<| j D ]2}| d¡rd|krd|krt| jdd |¡ƒS qW dS )zVCheck that .pyc files are only found within the site-packages or disutils directories.z.pyczsite-packagesZ	distutilsZC1139z(Found pyc file "{}" in invalid directoryN)r#   r<   r   r   r;   )r5   ro   r   r   r   Úcheck_for_pyc_in_site_packages7  s    z0CondaPackageCheck.check_for_pyc_in_site_packagesc             C   s:   x4| j D ]*}d|kr| d¡rt| jdd |¡ƒS qW dS )z(Check the tar archive for .pickle files.Zlib2to3z.pickleZC1140zFound lib2to3 .pickle file "{}"N)r#   r<   r   r   r;   )r5   ro   r   r   r   Úcheck_for_2to3_pickle=  s    z'CondaPackageCheck.check_for_2to3_picklec             C   sR   d| j krNxB| jD ]8}d|kr| d¡r|d | jkrt| jdd |¡ƒS qW dS )zGCheck that a .pyc file exists for every .py file in a Python 2 package.Zpy3z/site-packages/z.pyÚcZC1141z7Found python file "{}" without a corresponding pyc fileN)r    r#   r<   r   r   r;   )r5   ro   r   r   r   Úcheck_pyc_filesC  s
    
z!CondaPackageCheck.check_pyc_filesc             C   sh   dd„ | j D ƒ}t|ƒdkrJ|d }|d | j¡krdt| jdd |¡ƒS nt|ƒdkrdt| jdd	ƒS d
S )zKCheck that the Menu/package.json filename is identical to the package name.c             S   s$   g | ]}|  d ¡r| d¡r|‘qS )zMenu/z.json)rG   r<   )r   ro   r   r   r   rb   M  s    z:CondaPackageCheck.check_menu_json_name.<locals>.<listcomp>r8   r   z{}.jsonZC1142z!Found invalid Menu json file "{}"ZC1143z"Found more than one Menu json fileN)r#   rS   r;   r   r   r   )r5   Zmenu_json_filesre   r   r   r   Úcheck_menu_json_nameK  s    z&CondaPackageCheck.check_menu_json_namec          	   C   s¦   | j r¢| jd }|dkr,t| jdd |¡ƒS xt| j ¡ D ]f}|j d¡r8| j |j¡ 	d¡}t
|ƒ}|dkrt|dks„|d	kr8|d
kr8t| jdd |j||¡ƒS q8W dS )zGCheck that Windows package .exes and .dlls contain the correct headers.Úarch)Úx86Úx86_64ZC1144z,Found unrecognized Windows architecture "{}")z.exez.dlli   rŒ   zDLL I386r   z	DLL AMD64ZC1145z8Found file "{}" with object type "{}" but with arch "{}"N)r.   r*   r   r   r;   r   r"   r<   r$   r%   r	   r   )r5   r‹   r   Zfile_headerZfile_object_typer   r   r   Úcheck_windows_archW  s    
z$CondaPackageCheck.check_windows_archc             C   s¸   t  | j d¡¡}x | j ¡ D ]’}| ¡ r| j |j¡ 	¡ }t
 |¡ ¡ }xd|d D ]X}|j|d krT||d krˆt| jdd |j¡ƒS |j|d krTt| jdd	 |j¡ƒS qTW qW d
S )zCCheck the sha256 checksum and filesize of each file in the package.zutf-8r#   Ú_pathÚsha256ZC1146zDFound file "{}" with sha256 hash different than listed in paths.jsonZsize_in_bytesZC1147zAFound file "{}" with filesize different than listed in paths.jsonN)r'   r(   r,   r)   r   r"   Úisfiler$   r   r%   Úhashlibr   Ú	hexdigestr   r   r;   Úsize)r5   Z
paths_jsonr   Zfile_objectZsha256_digestr   r   r   r   Úcheck_package_hashes_and_sizeg  s    z/CondaPackageCheck.check_package_hashes_and_size),Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ústaticmethodr   rD   rI   rM   rN   rP   rU   rX   rY   rZ   r_   r`   rf   rg   rl   rm   rp   rq   rs   Úpropertyrt   ru   rz   r{   r}   r€   r   r‚   rƒ   r„   r…   r†   r‡   r‰   rŠ   rŽ   r•   Ú__classcell__r   r   )r6   r   r      sL   r   c                   sx   e Zd ZdZ‡ f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‡  ZS )ÚCondaRecipeCheckz1Create checks in order to validate conda recipes.c                sb   t t| ƒ ¡  || _|| _t d¡| _t d¡| _t d¡| _	t d¡t d¡t d¡dœ| _
dS )	z?Initialize conda recipe information for use with recipe checks.z[a-z0-9_][a-z0-9_\-\.]*$z[\w\.]+$z(ftp|http(s)?)://z[a-f0-9]{32}$z[a-f0-9]{40}$z[a-f0-9]{64}$)Úmd5Úsha1r   N)r   r   r   ÚmetaÚ
recipe_dirr/   r0   r1   r4   Úurl_patr3   )r5   r    r¡   )r6   r   r   r   z  s    zCondaRecipeCheck.__init__c             C   sz   | j  di ¡ dd¡}|dkr,t| jddƒS | j |¡rB| d¡rVt| jdd |¡ƒS t|ƒ}|rvt| jd	d
 |¡ƒS dS )z:Check the package name in meta.yaml for proper formatting.Úpackager   Ú ZC2101z!Missing package name in meta.yaml)r?   r   r@   ZC2102z,Found invalid package name "{}" in meta.yamlZC2103z+Found invalid sequence "{}" in package nameN)	r    rA   r   r¡   r1   rB   r<   r;   r   )r5   rC   r>   r   r   r   rD   †  s    z#CondaRecipeCheck.check_package_namec             C   sŽ   | j  di ¡ dd¡}|dkr,t| jddƒS t|tƒrŠ| j |¡rV| d¡sV| 	d¡rjt| jdd 
|¡ƒS t|ƒ}|rŠt| jd	d
 
|¡ƒS dS )z=Check the package version in meta.yaml for proper formatting.r£   r   r¤   ZC2104z$Missing package version in meta.yaml)r@   r?   ZC2105z/Found invalid package version "{}" in meta.yamlZC2106z.Found invalid sequence "{}" in package versionN)r    rA   r   r¡   Ú
isinstancerF   r4   rB   rG   r<   r;   r   )r5   rH   r>   r   r   r   rI   ”  s    
 z&CondaRecipeCheck.check_package_versionc             C   sb   | j  di ¡ d¡}|dk	r^y"t|ƒ}|dk r<t| jddƒS W n tk
r\   t| jddƒS X dS )	z:Check the build number in meta.yaml for proper formatting.r    ZnumberNr   ZC2108z<Build number in info/index.json cannot be a negative integerZC2107z2Build number in info/index.json must be an integer)r    rA   rK   r   r¡   rL   )r5   rJ   r   r   r   rM   £  s    z#CondaRecipeCheck.check_build_numberc          
   C   sÆ   xÀ| j D ]¶}|tkr0|dkr0t| jdd |¡ƒS |dkr| j  |¡}t|dƒr€xn|D ]&}|t| krTt| jdd ||¡ƒS qTW qx<|D ]4}x.|D ]&}|t| krt| jdd ||¡ƒS qW q†W qW dS )z4Check that the fields listed in meta.yaml are valid.ZextraZC2109zFound invalid section "{}"ÚkeysZC2110z(Found invalid field "{}" in section "{}"N)r    r   r   r¡   r;   rA   Úhasattr)r5   ZsectionZsubfieldÚkeyÚentryr   r   r   Úcheck_fields°  s    



zCondaRecipeCheck.check_fieldsc             C   s2  | j  di ¡ dg ¡}| j  di ¡ dg ¡}x¬|| D ] }| ¡ }|d }| j |¡sŽ||krrt| jdd |¡ƒS ||krŽt| jdd |¡ƒS t|ƒdkr¨t| jd	d
ƒS t|ƒdkr6t	t
|d ƒs6t| jdd |¡ƒS q6W t|ƒtt|ƒƒkrt| jdd |¡ƒS t|ƒtt|ƒƒkr.t| jdd |¡ƒS dS )z:Check that the requirements listed in meta.yaml are valid.Zrequirementsr    Úrunr   ZC2111z$Found invalid build requirement "{}"ZC2112z"Found invalid run requirement "{}"ZC2113z%Found empty dependencies in meta.yamlr   r8   ZC2114z*Found invalid dependency "{}" in meta.yamlZC2115z&Found duplicate build requirements: {}ZC2116z$Found duplicate run requirements: {}N)r    rA   rR   r1   rB   r   r¡   r;   rS   r   rT   r!   )r5   Zbuild_requirementsZrun_requirementsZrequirementZrequirement_partsZrequirement_namer   r   r   Úcheck_requirementsÄ  s$    z#CondaRecipeCheck.check_requirementsc             C   sÈ   | j  di ¡ d¡}|dk	r6t|ƒdkr6t| jddƒS | j  di ¡ d¡}| j  di ¡ d¡}| j  di ¡ d	¡}| j  di ¡ d
¡}x<||||gD ],}|dk	r”| j |¡s”t| jdd |¡ƒS q”W dS )z9Check the about field in meta.yaml for proper formatting.ÚaboutÚsummaryNéP   ZC2117z4Found summary with length greater than 80 charactersÚhomeÚdev_urlÚdoc_urlÚlicense_urlZC2118z#Found invalid URL "{}" in meta.yaml)r    rA   rS   r   r¡   r¢   rB   r;   )r5   r®   r°   r±   r²   r³   Úurlr   r   r   Úcheck_aboutß  s    zCondaRecipeCheck.check_aboutc             C   sÌ   t | j di ¡ƒ}x´|D ]¬}| d¡}|dk	r”| j |¡r€xXdD ]:}| |¡}|dk	r@| j|  |¡s@t| jdd |¡ƒS q@W nt| jdd |¡ƒS | d	¡}|r| d
¡r| d¡rt| jddƒS qW dS )z:Check the source field in meta.yaml for proper formatting.Úsourcer´   N)rž   rŸ   r   ZC2119z$Found invalid hash "{}" in meta.yamlZC2120z#Found invalid URL "{}" in meta.yamlÚgit_urlZgit_tagZ
git_branchZC2121z;Found both git_branch and git_tag in meta.yaml source field)	r
   r    rA   r¢   rB   r3   r   r¡   r;   )r5   Úsourcesr¶   r´   Zhash_algorithmr“   r·   r   r   r   Úcheck_sourceï  s    




zCondaRecipeCheck.check_sourcec             C   sN   | j  di ¡ d| j  di ¡ d¡¡}|dk	rJ|tkrJt| jdd |¡ƒS dS )z;Check that the license family listed in meta.yaml is valid.r­   rV   rW   NZC2122z!Found invalid license family "{}")r    rA   r   r   r¡   r;   )r5   rV   r   r   r   rX     s    z%CondaRecipeCheck.check_license_familyc             C   sÊ   | j  di ¡ dg ¡}| j  di ¡ dg ¡}t| j  di ¡ƒ}g }x|D ]}| | dg ¡¡ qHW xb|| | D ]R}tj | j|¡}| d¡r¢t	| jdd 
|¡ƒS tj |¡spt	| jd	d
 
|¡ƒS qpW dS )z/Check that the files listed in meta.yaml exist.ZtestÚfilesZsource_filesr¶   Zpatchesz..ZC2123z/Found file "{}" listed outside recipe directoryZC2124z/Found file "{}" in meta.yaml that doesn't existN)r    rA   r
   Úextendr9   r   Újoinr¡   rG   r   r;   Úexists)r5   Z
test_filesZtest_source_filesr¸   Zsource_patchesr¶   re   ro   r   r   r   Úcheck_for_valid_files  s    

z&CondaRecipeCheck.check_for_valid_filesc             C   s^   d}xTt  | j¡D ]D\}}}x8|D ]0}t j ||¡}| |¡r"t| jdd |¡ƒS q"W qW dS )z7Check for disallowed files inside the recipe directory.)
z.tarz.tar.gzz.tar.bz2z.tar.xzz.soz.dylibz.laz.az.dllz.pydZC2125z)Found disallowed file with extension "{}"N)r9   Úwalkr¡   r   r¼   r<   r   r;   )r5   Zdisallowed_extensionsÚdirpathr@   rd   re   ro   r   r   r   Úcheck_dir_content  s    

z"CondaRecipeCheck.check_dir_contentc          	   C   sf   t j | jd¡}t|ƒ}| ¡  ¡ }W dQ R X x0|D ](}| d¡r6|t ¡ kr6t	| jddƒS q6W dS )z9Check for default comments in conda-forge example recipe.z	meta.yamlNú#ZC2126z+Found conda-forge comment in meta.yaml file)
r9   r   r¼   r¡   r   r%   rc   rG   r   r   )r5   r    Z	meta_fileZreciperw   r   r   r   Úcheck_recipes_comments'  s    

z'CondaRecipeCheck.check_recipes_comments)r–   r—   r˜   r™   r   rD   rI   rM   rª   r¬   rµ   r¹   rX   r¾   rÁ   rÃ   rœ   r   r   )r6   r   r   w  s   r   )r™   r’   r'   r9   r/   r[   r   Zconda_verify.errorsr   r   Zconda_verify.constantsr   r   r   Zconda_verify.utilitiesr   r   r	   r
   r   rT   Úobjectr   r   r   r   r   r   Ú<module>
   s     ^