B
    `)                @   s  d Z ddlmZmZmZ e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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m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)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z? ddl@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJ ddlKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZT ddlUmVZVmWZW ddlXmYZYmZZZm[Z[m\Z\m]Z]m^Z^ ddl_m`Z` ddlambZb ddlcmdZdmeZemfZfmgZgmhZhmiZimjZjmkZk ddllmmZm ddlnmoZompZpmqZqmrZrmsZsmtZt ddlumvZv dZwdd Zxdd Zydd Zzdd Z{dd  Z|d!d" Z}dwd$d%Z~d&d' Zdxd(d)Zd*d+ Zdyd-d.Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Zd=d> Zd?d@ ZdAdB ZdCdD ZdEdF ZdzdGdHZd{dIdJZdKdL Zd|dMdNZdOdP ZdQdR ZdSdT Zd}dUdVZd~dWdXZdYdZ Zd[d\ Zd]d^ Zd_d` Zdadb Zdcdd Zdedf Zdgdh Zdidj Zdkdl ZG dmdn dnZG dodp dpe,ZG dqdr dre,ZG dsdt dteZG dudv dve,ZdS )zExecute Ansible tests.    )absolute_importdivisionprint_functionN   )types)WrappedThread)AnsibleCoreCISshKey)ManageWindowsCIManageNetworkCI)cloud_filter
cloud_initget_cloud_environmentget_cloud_platformsCloudEnvironmentConfig)	make_dirsopen_text_fileread_binary_fileread_text_filewrite_text_file)ApplicationWarningApplicationErrorSubprocessErrordisplayremove_treefind_executableraw_commandget_available_portgenerate_pip_commandfind_python	cmd_quoteANSIBLE_LIB_ROOTANSIBLE_TEST_DATA_ROOTANSIBLE_TEST_CONFIG_ROOTget_ansible_versiontempdiropen_zipfileSUPPORTED_PYTHON_VERSIONSstr_to_versionversion_to_str)
get_docker_completionget_network_settingsget_remote_completionget_python_pathintercept_commandnamed_temporary_filerun_commandwrite_json_test_results
ResultTypehandle_layout_messages)	docker_pull
docker_rundocker_available	docker_rmget_docker_container_idget_docker_container_ipget_docker_hostname!get_docker_preferred_network_nameis_docker_user_defined_network)ansible_environmentcheck_pyyaml)IntegrationTargetwalk_internal_targetswalk_posix_integration_targets walk_network_integration_targets walk_windows_integration_targetsTIntegrationTarget)get_ci_provider)categorize_changes)
TestConfigEnvironmentConfigIntegrationConfigNetworkIntegrationConfigPosixIntegrationConfigShellConfigWindowsIntegrationConfigTIntegrationConfig)ChangeDescription)integration_test_environmentintegration_test_config_filesetup_common_temp_dirget_inventory_relative_pathcheck_inventorydelegate_inventory)data_context)zansible.http.testszsni1.ansible.http.testszfail.ansible.http.testsc               C   s
   t   dS )z5Checks to perform at startup before running commands.N)check_legacy_modules rX   rX   N/home/dcms/DCMS/lib/python3.7/site-packages/ansible_test/_internal/executor.pycheck_startup   s    rZ   c              C   sD   x>dD ]6} d|  }x(t |D ]\}}}|rtd| qW qW dS )zTDetect conflicts with legacy core/extras module directories to avoid problems later.)coreextraszlib/ansible/modules/%sz[Files prohibited in "%s". These are most likely legacy modules from version 2.2 or earlier.N)oswalkr   )	directorypathrootZ
_dir_namesZ
file_namesrX   rX   rY   rW      s    
rW   c             C   s(   d}dg}|dd |D 7 }|| 7 }|S )z8
    :type command: list[str]
    :rtype: list[str]
    )TERMz/usr/bin/envc             S   s(   g | ] }|t jkrd |t j| f qS )z%s=%s)r]   environ).0varrX   rX   rY   
<listcomp>   s    z(create_shell_command.<locals>.<listcomp>rX   )commandZoptional_varscmdrX   rX   rY   create_shell_command   s
    ri   c          	   C   s   | ds\tt| |tjtdgdddd d }|r\tj	dt
||f dd	 t|S td
dd}|ryt|dgddd }W n tk
r   d}Y nX td|}|rt|d}tj	dt
| dd	 |S tj	ddd	 dS )zReturn the openssl version.z2.zsslcheck.pyT)capturealwaysr   versionz,Detected OpenSSL version %s under Python %s.r   )	verbosityZopensslF)required)rj    z,^OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+)z2Detected OpenSSL version %s using the openssl CLI.z!Unable to detect OpenSSL version.N)
startswithjsonloadsr0   r]   r`   joinr"   r   infor)   tupler   r   r   researchr(   group)argspythonpython_versionrl   Zopenssl_pathresultmatchrX   rX   rY   get_openssl_version   s$    
,
r~   c             C   sB   yt t|ddgddd S  tk
r<   | jr6t S  Y nX dS )z3Return the setuptools version for the given python.z-cz0import setuptools; print(setuptools.__version__)T)rj   r   N)r(   r   r   explainru   )ry   rz   rX   rX   rY   get_setuptools_version   s    r   c             C   sT   t |}t| |}t| ||}|dkrL|dkr4d}qP|rF|dk rFd}qPd}nd}|S )z
    Return the correct cryptography requirement for the given python version.
    The version of cryptography installed depends on the python version, setuptools version and openssl version.
    )      z2.6zcryptography < 2.2)r   r   r   zcryptography < 3.2zcryptography < 3.4zcryptography < 2.1)r   r   r~   )ry   r{   rz   setuptools_versionopenssl_versionZcryptographyrX   rX   rY   get_cryptography_requirement   s    
r   Fc          
      s  | j sttjj ttjj t| tr2| jr2dS | j	s<dS t| trJdS g }t| t
rx| jrh|d | jrx|d |s| j}tt|}y
tj}W n tk
r   i  }t_Y nX ||t   fdd|D }x|D ]}|| qW  | | jdkrNt| | t| t|ddgd	 t| t|dt| |gtjtd
d t|| j||dg}	t| t rx,t!| D ] }
|	t|d| j|
f  qxW dd |	D }	|	sdS t"|	dk}t| | t#| ||	|}|rt#| ||	|}|rt$dddd |D  | j%rtyt| |ddg dd W nB t&k
rr } z"|j'( dkr`t)*d n W dd}~X Y nX |rt+| |dd dS )z
    :type args: EnvironmentConfig
    :type python_version: str | None
    :type context: str | None
    :type enable_pyyaml_check: bool
    Ncoveragez	junit-xmlc                s   g | ]}| kr|qS rX   rX   )rd   package)installed_packagesrX   rY   rf   4  s    z0install_command_requirements.<locals>.<listcomp>sanityro   
setuptools)packageszcryptography-constraints.txt)r   constraints)r   contextz%s.cloud.%sc             S   s   g | ]}|r|qS rX   rX   )rd   rh   rX   rX   rY   rf   P  s    r   zcConflicts detected in requirements. The following commands reported changes during verification:
%s
c             s   s"   | ]}d  dd |D V  qdS ) c             s   s   | ]}t |V  qd S )N)r    )rd   crX   rX   rY   	<genexpr>b  s    z9install_command_requirements.<locals>.<genexpr>.<genexpr>N)rs   )rd   rh   rX   rX   rY   r   b  s    z/install_command_requirements.<locals>.<genexpr>checkz--disable-pip-version-checkT)rj   zERROR: unknown command "check"zQCannot check pip requirements for conflicts because "pip check" is not supported.F)rn   ),r   r   r2   COVERAGEr`   DATA
isinstancerL   rawrequirementsrG   r   appendjunitr{   r   r   install_command_requirementspackage_cacheAttributeError
setdefaultsetremoveupdaterg   !install_ansible_test_requirementsr0   generate_pip_installr   r]   rs   r"   rI   r   lenrun_pip_commandsr   Z	pip_checkr   stderrstripr   warningr>   )ry   r{   r   Zenable_pyyaml_checkr   pipr   Zskip_packagesr   commandsZcloud_platformdetect_pip_changeschangesexrX   )r   rY   r   
  st    










 
r   c             C   sb   y
t j}W n  tk
r*   t  }t _Y nX t||kr<dS t| t|ddd |t| dS )zQInstall requirements for ansible-test for the given pip if not already installed.Nzansible-testF)use_constraints)r   	installedr   r   ru   r0   r   add)ry   r   r   rX   rX   rY   r   s  s    
r   c             C   s`   g }|rt | |nd}xD|D ]<}|s&q|}t| | |rBt | |nd}||kr|| qW |S )z
    :type args: EnvironmentConfig
    :type pip: list[str]
    :type commands: list[list[str]]
    :type detect_pip_changes: bool
    :rtype: list[list[str]]
    N)pip_listr0   r   )ry   r   r   r   r   Z
after_listrh   Zbefore_listrX   rX   rY   r     s    

r   c             C   s   t | |dg ddd }|S )zP
    :type args: EnvironmentConfig
    :type pip: list[str]
    :rtype: str
    listT)rj   r   )r0   )ry   r   stdoutrX   rX   rY   r     s    r   Tc       	      C   s0  |pt jtdd}t jtdd|r0d||f n| }d}g }t j|rdt j|rd|d|g7 }|dkrt jjrt jt jj	dd	| }t j|rt j|r|d|g7 }|d
kr
t jt jj
d}t j|rt j|r|d|g7 }t jt jj
d}|dkrt jt jjd}t j|rPt j|rP|d|g7 }t jt jjd	| }t j|rt j|r|d|g7 }t jt jjd}|drt jt jjd}|r||7 }|sdS |r |rt j|rt j|r|d|g |d|g | ddg | S )z
    :type pip: list[str]
    :type command: str
    :type packages: list[str] | None
    :type constraints: str | None
    :type use_constraints: bool
    :type context: str | None
    :rtype: list[str] | None
    r   zconstraints.txtz%s.txtz%s.%sNz-rr   z
code-smellz%s.requirements.txtZunitszrequirements.txt)integrationzwindows-integrationznetwork-integrationzintegration.cloud.z-cinstallz--disable-pip-version-check)r]   r`   rs   r"   existsgetsizerV   contentZ
is_ansibleZsanity_pathZ	unit_pathintegration_pathrp   extend)	r   rg   r   r   r   r   r   Zcontent_constraintsoptionsrX   rX   rY   r     sD    
$

"r   c             C   s<   | j rt t|  | jr"t|  tddg}t| | dS )z!
    :type args: ShellConfig
    Zbashz-iN)delegateDelegater   inject_httptesterri   r0   )ry   rh   rX   rX   rY   command_shell  s    r   c             C   sV   t t jj t| }tjttj	|}t
tdd}t| |}t| ||| dS )z,
    :type args: PosixIntegrationConfig
    T)include_hiddenN)r3   rV   r   integration_messagesrS   r]   r`   rs   r"   basenameru   rA   command_integration_filtercommand_integration_filtered)ry   inventory_relative_pathinventory_pathall_targetsinternal_targetsrX   rX   rY   command_posix_integration  s    
r   c          	   C   s.  t t jj t| }tjttj	|d }| j
rVtjt jjt jj| j
}ntjt jj|}| jr~tj|}ntj|}| js| js|std||f t| | t| | ttdd}t| |td}g }| jrt| | j tdd | jjD }xb| jD ]X}	|	dd	\}
}||	}|s8qt t!"t#| |
||}d|_$|%  |&| qW x$t'd
d |D rt()d	 qnW dd |D }t*|}t+j,d||- f dd | jst.|| d}zt/| ||| d}W d| j0dks| j0dkr(|r(x|D ]}|j12  qW X dS )z.
    :type args: NetworkIntegrationConfig
    z	.templatezInventory not found: %s
Use --inventory to specify the inventory path.
Use --platform to provision resources and generate an inventory file.
See also inventory template: %sT)r   )init_callbackc             s   s   | ]}|d  |fV  qdS )platform_versionNrX   )rd   configrX   rX   rY   r   /  s    z.command_network_integration.<locals>.<genexpr>/r   c             s   s   | ]}|  V  qd S )N)is_alive)rd   instancerX   rX   rY   r   =  s    c             S   s   g | ]}|  qS rX   )wait_for_result)rd   r   rX   rX   rY   rf   @  s    z/command_network_integration.<locals>.<listcomp>z>>> Inventory: %s
%s   )rm   FNrk   success)3r3   rV   r   r   rS   r]   r`   rs   r#   r   	inventoryra   r   Zno_temp_workdirr   isfiler   platformr   rT   rU   ru   rB   r   network_initr-   python_executabledictmetadatainstance_configsplitgetr   	functoolspartialnetwork_rundaemonstartr   anytimesleepnetwork_inventoryr   rt   r   r   r   remote_terminater|   stop)ry   r   template_pathr   Zinventory_existsr   r   	instancesconfigsr   r   rl   r   r   remotesr   r   rX   rX   rY   command_network_integration	  sX     




r   c       	      C   s   | j s
dS | jjdk	rdS tdd |D }g }t|  xn| j D ]d}|dd\}}d| }||krxtd||f  q@tt	
t| ||}d|_|  || q@W x td	d |D rtd qW d
d |D | j_dS )z3Initialize platforms for network integration tests.Nc             s   s(   | ] }|j D ]}|d r|V  qqdS )znetwork/N)aliasesrp   )rd   targetarX   rX   rY   r   [  s    znetwork_init.<locals>.<genexpr>r   r   znetwork/%s/zESkipping "%s" because selected tests do not target the "%s" platform.Tc             s   s   | ]}|  V  qd S )N)r   )rd   r   rX   rX   rY   r   p  s    c             S   s   g | ]}|  qS rX   )r   )rd   r   rX   rX   rY   rf   s  s    z network_init.<locals>.<listcomp>)r   r   r   r   r	   r   r   r   r   r   r   network_startr   r   r   r   r   r   )	ry   r   Zplatform_targetsr   r   r   rl   Zplatform_targetr   rX   rX   rY   r   S  s*    r   c             C   s&   t | ||| j| jd}|  | S )zw
    :type args: NetworkIntegrationConfig
    :type platform: str
    :type version: str
    :rtype: AnsibleCoreCI
    )stageprovider)r   remote_stageremote_providerr   save)ry   r   rl   core_cirX   rX   rY   r   v  s    r   c             C   s>   t | ||| j| jdd}|| |  t|}|  |S )z
    :type args: NetworkIntegrationConfig
    :type platform: str
    :type version: str
    :type config: dict[str, str]
    :rtype: AnsibleCoreCI
    F)r   r   load)r   r   r   r   waitr   )ry   r   rl   r   r   managerX   rX   rY   r     s    
r   c       	   
      s   t dd | D }g }x| D ]}t |jj|jjtj|jjd t	|j
|j|j} |j ||j d|jddd fdd	t D f  ||j qW ||d
< d}x0|D ](}d|| }|td||f 7 }qW |}|S )z<
    :type remotes: list[AnsibleCoreCI]
    :rtype: str
    c             S   s   g | ]}|j g fqS rX   )r   )rd   remoterX   rX   rY   rf     s    z%network_inventory.<locals>.<listcomp>)ansible_hostansible_useransible_ssh_private_key_filez%s %s.-r   c             3   s   | ]}d | | f V  qdS )z%s="%s"NrX   )rd   k)r   rX   rY   r     s    z$network_inventory.<locals>.<genexpr>znet:childrenro   r   z!
        [%s]
        %s
        )r   
connectionhostnameusernamer]   r`   abspathssh_keykeyr+   ry   r   rl   r   Zinventory_varsr   namereplacers   sortedtextwrapdedent)	r   groupsnetr   settingstemplaterx   hostsr   rX   )r   rY   r     s,    

"
r   c                s  t t jj t }tjttj	|d } j
rVtjt jjt jj j
ntjt jj| js jstjstd|f t  t  ttdd}t |td}g }d}d}d} jrvt  j tdd  jjD }	xH jD ]>}
|	d	|
  }ttt |
|}d|_ |!  |"| qW x$t#d
d |D rjt$%d qHW dd |D t&}t'j(d|) f dd  jst*|  j+ot#dd |D }t,tj-.dd}|rt/ s|st'0d n||rv|r$t1d }dd| dd| gnd _2t3 \}4dd  fdd}fdd}dt$$  |}|} fdd }d} j5r j6sd!t$$  }d"|i}|d#| d}zt7 |||||d$ d}W d|rt8 | |rXt9 \}||d%}|d&| x@t:|D ]2}t;tj||}|<t=j>j W dQ R X qW W dQ R X  j?d'ksv j?d(kr|rx|D ]}|j@A  q|W X dS ))z.
    :type args: WindowsIntegrationConfig
    z	.templatezInventory not found: %s
Use --inventory to specify the inventory path.
Use --windows to provision resources and generate an inventory file.
See also inventory template: %sT)r   )r   Nc             s   s   | ]}|d  |fV  qdS )r   NrX   )rd   r   rX   rX   rY   r     s    z.command_windows_integration.<locals>.<genexpr>z
windows/%sc             s   s   | ]}|  V  qd S )N)r   )rd   r   rX   rX   rY   r     s    r   c             S   s   g | ]}|  qS rX   )r   )rd   r   rX   rX   rY   rf     s    z/command_windows_integration.<locals>.<listcomp>z>>> Inventory: %s
%sr   )rm   c             s   s   | ]}d |j kV  qdS )zneeds/httptester/N)r   )rd   r   rX   rX   rY   r     s    
HTTPTESTERFz>Assuming --disable-httptester since `docker` is not available.r   z-Rz
8080:%s:80z8443:%s:443z-fTc                s~   d| j krdS xjdd D D ]X}t|}|tjtdd ddtf } jd	krf|d
7 }|j	|dd qW dS )zA
                :type target: IntegrationTarget
                zneeds/httptester/Nc             S   s   g | ]}|j d kr|qS )2008)rl   )rd   rrX   rX   rY   rf     s    zJcommand_windows_integration.<locals>.forward_ssh_ports.<locals>.<listcomp>setupzwindows-httptester.ps1zHpowershell.exe -NoProfile -ExecutionPolicy Bypass -File .\%s -Hosts "%s"|r   z	 -VerboseF)r   	force_pty)
r   r
   uploadr]   r`   rs   r"   HTTPTESTER_HOSTSrm   ssh)r   r   r   script)ry   r   ssh_optionswatcher_pathrX   rY   forward_ssh_ports  s    

z6command_windows_integration.<locals>.forward_ssh_portsc                sD   d| j krdS x0dd  D D ]}t|}|jd dd qW dS )zA
                :type target: IntegrationTarget
                zneeds/httptester/Nc             S   s   g | ]}|j d kr|qS )r  )rl   )rd   r  rX   rX   rY   rf   +  s    zJcommand_windows_integration.<locals>.cleanup_ssh_ports.<locals>.<listcomp>zcmd.exe /c "del %s /F /Q"F)r  )r   r
   r  )r   r   r   )r   r  rX   rY   cleanup_ssh_ports$  s
    
z6command_windows_integration.<locals>.cleanup_ssh_portsz ansible-test-http-watcher-%s.ps1c                s^   t jtd| }dd|dt|g} jr@|dd j   t }t	 |d|dd	 d S )
NZ	playbookszansible-playbookz-iz-ez-%svro   T)Zdisable_coverage)
r]   r`   rs   r"   rq   dumpsrm   r   r=   r.   )playbookZrun_playbook_varsplaybook_pathrg   env)ry   r   rX   rY   run_playbook4  s    z1command_windows_integration.<locals>.run_playbookzC:\ansible_test_coverage_%sremote_temp_pathzwindows_coverage_setup.yml)
pre_targetpost_targetr$  )r$  local_temp_pathzwindows_coverage_teardown.ymlrk   r   )Br3   rV   r   r   rS   r]   r`   rs   r#   r   r   ra   r   r   windowsr   r   rT   rU   ru   rC   r   windows_initr-   r   r   r   r   r   r   r   windows_runr   r   r   r   r   r   windows_inventoryr   rt   r   r   
httptesterboolrc   r   r6   r   r  r   start_httptesterinsertr   coverage_checkr   r7   r%   listdirr&   
extractallr2   r   r   r|   r   )ry   r   r   r   r   r   r%  r&  httptester_idr   rl   r   r   r   Zuse_httptesterZdocker_httptesterZ
first_hostr  r  r#  r$  Zplaybook_varsr   r'  filenameZcoverage_ziprX   )ry   r   r   r  r  rY   command_windows_integration  s     


	




(
r5  c             C   s   | j s
dS | jjdk	rdS g }x8| j D ].}ttt| |}d|_|  |	| q&W x t
dd |D rxtd qZW dd |D | j_dS )zc
    :type args: WindowsIntegrationConfig
    :type internal_targets: tuple[IntegrationTarget]
    NTc             s   s   | ]}|  V  qd S )N)r   )rd   r   rX   rX   rY   r   r  s    zwindows_init.<locals>.<genexpr>r   c             S   s   g | ]}|  qS rX   )r   )rd   r   rX   rX   rY   rf   u  s    z windows_init.<locals>.<listcomp>)r(  r   r   r   r   r   windows_startr   r   r   r   r   r   )ry   r   r   rl   r   rX   rX   rY   r)  _  s    r)  c             C   s&   t | d|| j| jd}|  | S )z_
    :type args: WindowsIntegrationConfig
    :type version: str
    :rtype: AnsibleCoreCI
    r(  )r   r   )r   r   r   r   r   )ry   rl   r   rX   rX   rY   r6  x  s    r6  c             C   s>   t | d|| j| jdd}|| |  t|}|  |S )z
    :type args: WindowsIntegrationConfig
    :type version: str
    :type config: dict[str, str]
    :rtype: AnsibleCoreCI
    r(  F)r   r   r   )r   r   r   r   r   r
   )ry   rl   r   r   r   rX   rX   rY   r*    s    
r*  c          
      s   g }x| D ]}t |jj|jj|jj|jjd |jrHtj	|jj
 d< |jdkrd jdddd n.|jdkr jd	dd
ddd n jd	dd |d|jddd fddt D f  q
W d}t|}|d| }|S )z<
    :type remotes: list[AnsibleCoreCI]
    :rtype: str
    )r   r   Zansible_passwordansible_portr   zwindows-2008Zpsrpbasicignore)ansible_connectionZansible_psrp_authZansible_psrp_cert_validationzwindows-2016ZwinrmZntlmhttpZ5985)r:  $ansible_winrm_server_cert_validationZansible_winrm_transportZansible_winrm_schemer7  )r:  r<  z%s %sr   _r   c             3   s   | ]}d | | f V  qdS )z%s="%s"NrX   )rd   r   )r   rX   rY   r     s    z$windows_inventory.<locals>.<genexpr>z|
    [windows]
    %s

    # support winrm binary module tests (temporary solution)
    [testhost:children]
    windows
    r   )r   r   r  r  passwordportr  r]   r`   r  r  r  r   r   r  rs   r  r	  r
  )r   r  r   r  r   rX   )r   rY   r+    s@    




&
r+  c       	         s  t dd |D }t } j|kr jdkr^ j jkr^ j j   jd jg7  _n$ jdkr j jkr j j  j| } j}t	| j||}t
 |}|t |7 }|r||7 }t	| j||}|st  jrt fdd|D std j |r| | t | tjt jjt jjtjrhfdd	}t |  jr~t|||d
t  |S )z*Filter the given integration test targets.c             s   s   | ]}d |j kr|V  qdS )zhidden/N)r   )rd   r   rX   rX   rY   r     s    z-command_integration_filter.<locals>.<genexpr>includez	--includeexcludec             3   s   | ]}|j  jkV  qd S )N)r  start_at)rd   r   )ry   rX   rY   r     s    z#Start at target matches nothing: %sc                s   |   t jjf dS )z
            Add the integration config vars file to the payload file list.
            This will preserve the file during delegation even if the file is ignored by source control.
            N)r   rV   r   integration_vars_path)files)vars_file_srcrX   rY   integration_config_callback   s    z?command_integration_filter.<locals>.integration_config_callback)requirerA  integration_targets)ru   get_changes_filterZchanged_all_targetZchanged_all_moder@  r   Zdelegate_argsrA  rG  r@   get_integration_filterr   AllTargetsSkippedrB  r   r   r   r]   r`   rs   rV   r   ra   rC  r   Zregister_payload_callbackr   r   r   )	ry   targetsr   r   rG  rA  r   Zenvironment_excluderF  rX   )ry   rE  rY   r     s>    


 

r   c       %      C   s  d}g }g }	t |}
tdd |D }g }t }x>|D ]6}x0|j|j D ] }||krH|d|j|f  qHW q6W |rtdt|d	|f t
| | j tj	tjjd}| jsVtdd |D rVd	}td
 x~td|d D ]l}y(t| dddddgdd td P W q tk
rP   ||kr0 d}td|  t| Y qX qW | jrrt| tsrt|  | j}i }d}dd	dd tdD  }t| | zx|
D ]}| jr|s|j| jk}|sܐq| j rt!|j q| j"rdnd}| j#}t$| |}|r|nt%| }d}tjd| dd zNyАx||r|d8 }y|rf|  t&| ||j||||d t }t&| ||j||||d | jst'| t(| |r|| z<|j)rt*| |||||d nt+| ||||||d d}W d|r|| X t }t|j|j,|j-|j.t/|| |j|j| j0| j1| jd
||j< P W n` tk
r   |r~|2|| |j3|jdd s |s td!|j  d" t_#| _#Y nX qFW t }t%| }t }t%j4|||jdd  t/|| ||j d#< || W nv t5k
r } zV|	| | j6rDt7| wt8d$|j  t9|
d}|rtt8d%|j   W dd}~X Y nX W d| t_#| _#X qW W d| jsN| j0rtj	|tj:j} tj:j}!x4t;| D ]&}"t<=tj	| |"tj	|!|" qW t'| d&| j>t?@d'd(tAtBjBC jDd)d*f }#t|d+}$tEtjF|#|$ X |	rtd,t|	t|t|	 d	d-d |	D f dS ).a;  
    :type args: IntegrationConfig
    :type targets: tuple[IntegrationTarget]
    :type all_targets: tuple[IntegrationTarget]
    :type inventory_path: str
    :type pre_target: (IntegrationTarget) -> None | None
    :type post_target: (IntegrationTarget) -> None | None
    :type remote_temp_path: str | None
    Fc             s   s   | ]}|j |fV  qd S )N)r  )rd   r   rX   rX   rY   r   !  s    z/command_integration_filtered.<locals>.<genexpr>z-Target "%s" contains invalid setup target: %sz"Found %d invalid setup aliases:
%sr   
output_dirc             s   s   | ]}d |j kV  qdS )z
needs/ssh/N)r   )rd   r   rX   rX   rY   r   2  s       zESSH service required for tests. Checking to make sure we can connect.r   r  z-ozBatchMode=yes	localhostidT)rj   zSSH service responded.r   zGSSH service not responding. Waiting %d second(s) before checking again.Nz/tmp/ansible-test-%sro   c             s   s    | ]}t tjtj V  qd S )N)randomchoicestringascii_lettersdigits)rd   Z_idxrX   rX   rY   r   M  s          z>>> Environment Description
%s)rm   )r$  )
r  typer   modulesZrun_time_seconds
setup_oncesetup_alwaysr   coverage_labelr{   )throwz1Retrying test target "%s" with maximum verbosity.   Zvalidation_secondsz<To resume at this test target, use the option: --start-at %sz?To resume after this test target, use the option: --start-at %sz
%s-%s.jsonz[^0-9]r   r   )microsecond)rL  zbThe %d integration test(s) listed below (out of %d) failed. See error output above for details:
%sc             s   s   | ]}|j V  qd S )N)r  )rd   r   rX   rX   rY   r     s    )Giterr   r   rZ  r[  r   r  r   r   rs   r>   r{   r]   r`   r2   TMPr   r   r   rt   ranger0   r   r   r   r   r   r   rM   start_at_taskrR   rB  Zlist_targetsprintZretry_on_errorrm   r   EnvironmentDescriptionrun_setup_targetsr   r   script_pathcommand_integration_scriptcommand_integration_rolerX  r   rY  intr   r\  Z
on_failurevalidater   	ExceptionZcontinue_on_errorerrornoticenextr   r1  shutilcopyrg   rv   substrdatetimeutcnowr  r1   r   )%ry   rL  r   r   r%  r&  r$  foundZpassedfailedZtargets_iterZall_targets_dictZsetup_errorsZsetup_targets_executedr   Zsetup_targettest_dirZ	max_triesisecondsrc  resultscurrent_environmentZcommon_temp_pathtriesrm   cloud_environmentZoriginal_environment
start_timeZend_timer   Znext_targetZcoverage_temp_pathZcoverage_save_pathr4  Zresult_namedatarX   rX   rY   r     s    














&(r   c             C   s   t dddt dddg}t }|s:x|D ]}t |d< q(W t| | j t| t dd |D }|rt| |}tjd	| d
d nt	 }g }x2|D ]*}|dd|d ||
d|d f g7 }qW ||fS )zB
    :type args: EnvironmentConfig
    :rtype: str, list[str]
    i  P   )r   	containeri   i  rO  c             s   s&   | ]}d |kr|d  |d fV  qdS )rO  r  NrX   )rd   r?  rX   rX   rY   r     s    z#start_httptester.<locals>.<genexpr>z&Found httptester container address: %sr   )rm   z-Rz%d:%s:%dr   r  )r   r8   r   r4   r,  run_httptesterr9   r   rt   r:   r   )ry   portsZcontainer_iditemr3  Zcontainer_hostr  r?  rX   rX   rY   r.    s(    	



*r.  c             C   s   dg}|r4x(|  D ]\}}|dd||f g7 }qW t| }t|r`xtD ]}|d|g qJW t| | j|dd }| jrd}n| }|S )z^
    :type args: EnvironmentConfig
    :type ports: dict[int, int] | None
    :rtype: str
    z--detachz-pz%d:%dz--network-alias)r   r   r3  )	itemsr;   r<   r  r   r5   r,  r   r   )ry   r  r   Zlocalhost_portZcontainer_portnetworkaliasr3  rX   rX   rY   r    s    
r  c                s  d  fddt D }d}t|d}t fdd|D sRt|d||  td	d
d}tdd
d}|rtdd
d}|ryt| ddgdd W n tk
r   Y nX d}d	ddg}yt| |d|d W n tk
r   Y nX n|rddg}	x|	D ]\}
}dddddt	|
dddt	|g
}y$dddd d!g| }t| |dd W q tk
rz   dddd"d!g| }t| |dd Y qX qW nt
d#d$S )%z"
    :type args: CommonConfig
    z # ansible-test httptester
c                s   g | ]}d | f qS )z127.0.0.1 %s%srX   )rd   host)commentrX   rY   rf   )  s    z%inject_httptester.<locals>.<listcomp>z
/etc/hostsTc             3   s   | ]}|  V  qd S )N)endswith)rd   line)r  rX   rY   r   .  s    z$inject_httptester.<locals>.<genexpr>ro   pfctlF)rn   iptableskldloadpf)rj   z
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
rdr pass inet proto tcp from any to any port 443 -> 127.0.0.1 port 8443
z-efr   )rj   r  )r  i  )i  i   z-oloz-pZtcpz--dportz-jZREDIRECTz	--to-portz-tZnatz-CZOUTPUTz-Az0No supported port forwarding mechanism detected.N)r  r   
splitlinesr   r   rs   r   r0   r   rs  r   )ry   Zappend_linesZ
hosts_pathZoriginal_linesr  r  r  rulesrh   r  srcdstZrulerX   )r  rY   r   $  sB    
 r   c       
      C   sr   xl|D ]d}|s||krq|| }	| j s6t| t| |	jrNt| |	||| nt| |	d||| || qW dS )a	  
    :type args: IntegrationConfig
    :type test_dir: str
    :type target_names: list[str]
    :type targets_dict: dict[str, IntegrationTarget]
    :type targets_executed: set[str]
    :type inventory_path: str
    :type temp_path: str
    :type always: bool
    N)r   r   r   rg  rh  ri  r   )
ry   rx  Ztarget_namesZtargets_dictZtargets_executedr   	temp_pathrk   target_namer   rX   rX   rY   rf  ^  s    
rf  c       	   	   C   s   t | |d}| jr"|tdd dg|r4|jp6g ng  }ttjjdt	t
|| jjp`t j| jrjdn| jrtdnd|tj|d	}| jr|td
d d|jkr| jrtd|j  |tdd || |S )z
    :type args: IntegrationConfig
    :type target: IntegrationTarget
    :type test_dir: str
    :type inventory_path: str
    :type ansible_config: str | None
    :type env_config: CloudEnvironmentConfig | None
    :rtype: dict[str, str]
    )ansible_config1)r  r   ,r   yesro   )ZJUNIT_OUTPUT_DIRZANSIBLE_CALLBACK_WHITELISTZANSIBLE_TEST_CIZANSIBLE_TEST_COVERAGEZ
OUTPUT_DIRZINVENTORY_PATHdebug)ZANSIBLE_STRATEGYz
non_local/zESkipping coverage reporting on Ansible modules for non-local test: %s)ZANSIBLE_TEST_REMOTE_INTERPRETER)r=   r   r   r   callback_pluginsr2   ZJUNITr`   rs   r  r   r   Zci_providerrE   coder0  r   r]   r  Zdebug_strategyr   r   r   r  )	ry   r   rx  r   r  
env_configr"  r  r   rX   rX   rY   integration_environment|  s(    



r  c             C   s  t d|j  d}t| tr4t| |}|r4| }t| ||}dtj	
|j g}	| jrp|	dd| j   t| |||j|j|}
tj	|j|j}|
t|d |r|jr|
|j t| ||j>}|r|	dd| g7 }	d	|jk}t| |	|j|
||||d
 W dQ R X W dQ R X dS )z
    :type args: IntegrationConfig
    :type target: IntegrationTarget
    :type test_dir: str
    :type inventory_path: str
    :type temp_path: str
    :type remote_temp_path: str | None
    z"Running %s integration test scriptNz./%sr   r  )ANSIBLE_PLAYBOOK_DIRz-ez@%sz
non_local/)r  r"  cwdr  r$  module_coverage)r   rt   r  r   rK   r   get_environment_configrP   r]   r`   r   rg  rm   r   r  r   r  rs   targets_dirrelative_pathr   r   env_varsrQ   integration_dirr   r.   )ry   r   rx  r   r  r$  r  r~  test_envrh   r"  r  Zconfig_pathr  rX   rX   rY   rh    s,    	




rh  c             C   sf  t d|j  d}g }t|d}	t| trFd}
d}|	tdd n4t| tr\|j}
d}nd}
d	}t	| |}|rz|
 }t| ||}tj|jr|tj|j|j t|
|||	|jgd
}|r|jr|	|j |t|j|jd tj|gdd	d}t| |jd|j d|d2}tj|}t jd|| f dd d|dtj|j|jg}|rt|d|g7 }| jr|d| jg7 }| jr|d| jg7 }| jr|dg7 }t| tr| jr|dd| j g7 }| j r|dd| j    t!| |||j|j"|}|j}|t|d |j#|d< d |j$k}t%| ||j|||||d! W dQ R X W dQ R X dS )"z
    :type args: IntegrationConfig
    :type target: IntegrationTarget
    :type start_at_task: str | None
    :type test_dir: str
    :type inventory_path: str
    :type temp_path: str
    :type remote_temp_path: str | None
    z Running %s integration test roleN)rM  r(  FzC:\ansible_testing)Zwin_output_dirZtesthostT)r  gather_facts
vars_filesvarsZroles)environmentmodule_defaults   )indent	sort_keysz%s-z.yml)ry   r_   prefixsuffixr   z>>> Playbook: %s
%sr   )rm   zansible-playbookz-iz--start-at-taskz--tagsz--skip-tagsz--diffz-eztestcase=%sr   r  )r  ZANSIBLE_ROLES_PATHz
non_local/)r  r"  r  r  r$  r  )&r   rt   r  r   r   rM   r   rJ   Znetwork_platformr   r  rP   r]   r`   r   Z	vars_filer   relpathr  Zansible_varsr  r  rq   r  r/   r   r   r   tagsZ	skip_tagsZdiffZtestcaserm   r  r  r  r   r.   )ry   r   rc  rx  r   r  r$  r  r  	variablesr  r  r~  r  Zplayr   r!  r4  rh   r"  r  r  rX   rX   rY   ri    sv    







ri  c             C   sf   t | }| jjs2|r$t| || j}nt }|| j_|dkr>g S |sHt | jjjdkr\t | jjjS )z6
    :type args: TestConfig
    :rtype: list[str]
    N)	detect_changesr   change_descriptionrF   rg   rO   NoChangesDetectedrL  NoTestsForChanges)ry   pathsr   rX   rX   rY   rI  :  s    rI  c             C   s   | j rt | }n4| js | jrD| jp(g }| jrH|t| j 7 }ndS |dkrTdS tdt	|  x|D ]}tj|dd qlW |S )z=
    :type args: TestConfig
    :rtype: list[str] | None
    NzDetected changes in %d file(s).r   )rm   )
changedrE   r  Zchanged_fromZchanged_pathr   r  r   rt   r   )ry   r  r`   rX   rX   rY   r  U  s    

r  c             C   s*   | j rt| |S | jr t| |S t| |S )zi
    :type args: IntegrationConfig
    :type targets: tuple[IntegrationTarget]
    :rtype: list[str]
    )Zdockerget_integration_docker_filterr   get_integration_remote_filterget_integration_local_filter)ry   rL  rX   rX   rY   rJ  n  s
    

rJ  c          	      s  t dd | jD | jspdfdd|D   fdd|D }|rp|| tddd	|f  t d
d | jD | jsdfdd|D   fdd|D }|r|| tddd	|f  t dd | jD | j	rt | j
jjpg O | jstdfdd|D   fdd|D }|rt|| tddd	|f  t| tr| jrg }g }x|D ]}d|jkrqg }g }x6| jD ],}	d|	 |jkr||	 n
||	 qW |r
|r
||j||f n|r||j qW |rj|| dd | jD }
tdd|
d	| jd	|f  |rx4|D ],\}}}td|d	|d	|f  qvW dS )zp
    :type args: IntegrationConfig
    :type targets: tuple[IntegrationTarget]
    :type exclude: list[str]
    c             s   s   | ]}| d r|V  qdS )z	disabled/N)rp   )rd   r   rX   rX   rY   r     s    z,common_integration_filter.<locals>.<genexpr>z	disabled/c                s    g | ]} t |j@ r|jqS rX   )r   r   r  )rd   r   )override_disabledrX   rY   rf     s    z-common_integration_filter.<locals>.<listcomp>c                s&   g | ]}|j kr|j kr|jqS rX   )r   r  )rd   r   )overrideskiprX   rY   rf     s    z\Excluding tests marked "%s" which require --allow-disabled or prefixing with "disabled/": %sr   z, c             s   s   | ]}| d r|V  qdS )zunsupported/N)rp   )rd   r   rX   rX   rY   r     s    zunsupported/c                s    g | ]} t |j@ r|jqS rX   )r   r   r  )rd   r   )override_unsupportedrX   rY   rf     s    c                s&   g | ]}|j kr|j kr|jqS rX   )r   r  )rd   r   )r  r  rX   rY   rf     s    zbExcluding tests marked "%s" which require --allow-unsupported or prefixing with "unsupported/": %sc             s   s   | ]}| d r|V  qdS )z	unstable/N)rp   )rd   r   rX   rX   rY   r     s    z	unstable/c                s    g | ]} t |j@ r|jqS rX   )r   r   r  )rd   r   )override_unstablerX   rY   rf     s    c                s&   g | ]}|j kr|j kr|jqS rX   )r   r  )rd   r   )r  r  rX   rY   rf     s    z\Excluding tests marked "%s" which require --allow-unstable or prefixing with "unstable/": %szskip/windows/zskip/windows/%s/c             S   s   g | ]}d | qS )zskip/windows/%s/rX   )rd   wrX   rX   rY   rf     s    zGExcluding tests marked "%s" which are set to skip with --windows %s: %sz", "zIIncluding test "%s" which was marked to skip for --windows %s but not %s.N)r   r@  Zallow_disabledr   r   r   rstriprs   Zallow_unsupportedZallow_unstable_changedr   r  Zfocused_targetsZallow_unstabler   rM   r(  r   r   r  )ry   rL  rA  skippedZall_skippedZnot_skippedr   Z
skip_validZskip_missingrl   Zskip_aliasesrX   )r  r  r  r  r  rY   common_integration_filter}  sl    




"r  c                s   g }t | || | jsdt dkrddfdd|D }|rd| tddd|f  t	dd	 | j
D | jsd
fdd|D   fdd|D }|r|| tddd|f  t|| j| |S )zi
    :type args: IntegrationConfig
    :type targets: tuple[IntegrationTarget]
    :rtype: list[str]
    r   zneeds/root/c                s   g | ]} |j kr|jqS rX   )r   r  )rd   r   )r  rX   rY   rf     s    z0get_integration_local_filter.<locals>.<listcomp>zMExcluding tests marked "%s" which require --allow-root or running as root: %sr   z, c             s   s   | ]}| d r|V  qdS )zdestructive/N)rp   )rd   r   rX   rX   rY   r     s    z/get_integration_local_filter.<locals>.<genexpr>zdestructive/c                s    g | ]} t |j@ r|jqS rX   )r   r   r  )rd   r   )override_destructiverX   rY   rf     s    c                s&   g | ]}|j kr|j kr|jqS rX   )r   r  )rd   r   )r  r  rX   rY   rf     s    zqExcluding tests marked "%s" which require --allow-destructive or prefixing with "destructive/" to run locally: %s)r  Z
allow_rootr]   getuidr   r   r   r  rs   r   r@  Zallow_destructiver   !exclude_targets_by_python_versionr{   )ry   rL  rA  r  rX   )r  r  r  rY   r    s(    

r  c                s   g }t | || d  fdd|D }|rR|  td dd|f  | jsd  fdd|D }|r|  td	 dd|f  t| t | j	}t
||| |S )
zi
    :type args: IntegrationConfig
    :type targets: tuple[IntegrationTarget]
    :rtype: list[str]
    zskip/docker/c                s   g | ]} |j kr|jqS rX   )r   r  )rd   r   )r  rX   rY   rf     s    z1get_integration_docker_filter.<locals>.<listcomp>z=Excluding tests marked "%s" which cannot run under docker: %sr   z, zneeds/privileged/c                s   g | ]} |j kr|jqS rX   )r   r  )rd   r   )r  rX   rY   rf     s    zUExcluding tests marked "%s" which require --docker-privileged to run under docker: %s)r  r   r   r   r  rs   Zdocker_privilegedget_python_versionr*   Z
docker_rawr  )ry   rL  rA  r  r{   rX   )r  rY   r    s$    

r  c          	      s"  | j }g }t| || d|j |jd|j|jf d|j|jf d|j|jf d|j|jf i}|jr|d|j|jf d|j|jf d|j|j|jf d|j|j|jf i xR| D ]F\ } fdd	|D }|r| d
  t	d |d
|f  qW t| t | j}t||| |S )zi
    :type args: IntegrationConfig
    :type targets: tuple[IntegrationTarget]
    :rtype: list[str]
    zskip/%sz
skip/%s/%sz%s %sz	skip/%s%sz%s on %szskip/%s/%s/%sz%s %s on %sc                s   g | ]} |j kr|jqS rX   )skipsr  )rd   r   )r  rX   rY   rf   %  s    z1get_integration_remote_filter.<locals>.<listcomp>r   z=Excluding tests marked "%s" which are not supported on %s: %sz, )Zparsed_remoter  r   rl   archr   r  r   r   r   rs   r  r,   r   r  )ry   rL  r   rA  r  descriptionr  r{   rX   )r  rY   r    s$     *r  c                s   |st d dS |dd }d|   fdd| D }|rh|  t d d	|d
|f  d|   fdd| D }|r|  t d d	|d
|f  dS )zl
    :type targets: tuple[IntegrationTarget]
    :type python_version: str
    :type exclude: list[str]
    zEPython version unknown. Unable to skip tests based on Python version.Nr   r   zskip/python%s/c                s   g | ]} |j kr|jqS rX   )r   r  )rd   r   )r  rX   rY   rf   >  s    z5exclude_targets_by_python_version.<locals>.<listcomp>zDExcluding tests marked "%s" which are not supported on python %s: %sr   z, c                s   g | ]} |j kr|jqS rX   )r   r  )rd   r   )r  rX   rY   rf   E  s    )r   r   r   r   r  rs   )rL  r{   rA  Zpython_major_versionr  rX   )r  rY   r  1  s     


r  c             C   s   | |i }| d}|r|s<| jr*| jS tjddd dS |d}|d }| jr|| j|kr|td| j|d	t|f | jp|}|S )
zh
    :type args: EnvironmentConfig
    :type configs: dict[str, dict[str, str]]
    :type name: str
    rz   zYNo Python version specified. Use completion config or the --python option to specify one.T)uniquero   r  r   zEPython %s is not supported by %s. Supported Python version(s) are: %sz, )r   rz   r   r   r   r   rs   r  )ry   r   r  r   Zconfig_pythonZsupported_python_versionsZdefault_python_versionr{   rX   rX   rY   r  L  s    


r  c             C   s   | j r| j S ||i }|sH| jr.d| j }nd}tjd| dd |S t| ||}|dd}tj|d| }|d| |}|S )zh
    :type args: EnvironmentConfig
    :type configs: dict[str, dict[str, str]]
    :type name: str
    zpython%srz   zsUsing "%s" as the Python interpreter. Use completion config or the --python-interpreter option to specify the path.T)r  
python_dirz/usr/bin)	python_interpreterr   rz   r   r   r  r]   r`   rs   )ry   r   r  r   guessr{   r  r  rX   rX   rY   get_python_interpreterj  s    r  c               @   sd   e Zd ZdZdd Zedd Zdd Zdd	 Zed
d Z	edd Z
edd Zedd ZdS )re  z+Description of current running environment.c                s&  |_ j jri _dS g dg}|t7 }|ttdd tD 7 }tjt	dt
dd t|D t
dd t|D  t
fddtD }t
 fd	dt D }tjd
}x"t|D ]}| | qW xD ]}tj|dd qW t
 |||d_dS )z`Initialize snapshot of environment configuration.
        :type args: IntegrationConfig
        Nro   c             s   s   | ]}| d d V  qdS )r   r   N)r   )rd   r  rX   rX   rY   r     s    z2EnvironmentDescription.__init__.<locals>.<genexpr>zversions.pyc             s   s"   | ]}|t d | ddfV  qdS )zpython%sF)rn   N)r   )rd   r  rX   rX   rY   r     s    c             s   s"   | ]}|t d | ddfV  qdS )zpip%sF)rn   N)r   )rd   r  rX   rX   rY   r     s    c             3   s.   | ]&} | r|  | gfV  qd S )N)get_version)rd   r  )python_pathsselfversion_checkwarningsrX   rY   r     s    c             3   s(   | ] } | r|  | fV  qd S )N)get_shebang)rd   r  )	pip_pathsr  rX   rY   r     s    z~/.ssh/known_hostsT)r  )r  r  program_versionspip_interpretersknown_hosts_hashr  )ry   r   r  r'   r   r   r]   r`   rs   r"   r   r  get_hash
expandusercheck_python_pip_associationr   r   )r  ry   versionsr  r  r  rl   r   rX   )r  r  r  r  r  rY   __init__  s2     
zEnvironmentDescription.__init__c             C   s  d| rd|  nd }| | }| | }|s4|s4dS |sN|d||f  dS |sh|d||f  dS | | }td|}	|	s|d|||f  dS tj|	d	}
tj|}|
|krdS yt	|
|}W n t
k
r   d
}Y nX |rdS |d|||
|f  dS )z
        :type version: str
        :param python_paths: dict[str, str]
        :param pip_paths:  dict[str, str]
        :param pip_interpreters:  dict[str, str]
        :param warnings: list[str]
        zPython%sz %sro   NzEA %s interpreter was not found, yet a matching pip was found at "%s".zEA %s interpreter was found at "%s", yet a matching pip was not found.z#!\s*(?P<command>[^\s]+)zDA %s pip was found at "%s", but it does not have a valid shebang: %srg   FzIA %s pip was found at "%s", but it uses interpreter "%s" instead of "%s".)r   r   rv   rw   r]   r`   realpathrx   filecmpcmpOSError)rl   r  r  r  r  Zpython_labelZpip_pathZpython_pathZpip_shebangr}   Zpip_interpreterr  Z	identicalrX   rX   rY   r    s8    	



z3EnvironmentDescription.check_python_pip_associationc             C   s   t j| jdddS )z
        :rtype: str
        Tr  )r  r  )rq   r  r  )r  rX   rX   rY   __str__  s    zEnvironmentDescription.__str__c             C   s   t | j}| | |||S )zW
        :type target_name: str
        :type throw: bool
        :rtype: bool
        )re  ry   r   )r  r  r]  currentrX   rX   rY   rk    s    
zEnvironmentDescription.validatec          	   C   sh   t | }t |}||krdS dtj| | dddd}d||||f }|rZt|t| dS )	z
        :type original: EnvironmentDescription
        :type current: EnvironmentDescription
        :type target_name: str
        :type throw: bool
        :rtype: bool
        Tr   zoriginal.jsonzcurrent.jsonro   )r   bZfromfileZtofileZlinetermzTest target "%s" has changed the test environment!
If these changes are necessary, they must be reverted before the test finishes.
>>> Original Environment
%s
>>> Current Environment
%s
>>> Environment Diff
%sF)rs  rs   difflibunified_diffr  r   r   rm  )originalr  r  r]  Zoriginal_jsonZcurrent_jsonr  messagerX   rX   rY   r     s     	

zEnvironmentDescription.checkc          
   C   sn   yt | ddd\}}W n0 tk
rF } z|d|  dS d}~X Y nX dd |pTd |p^d   D S )	zg
        :type command: list[str]
        :type warnings: list[text]
        :rtype: list[str]
        TrW  )rj   Zcmd_verbosityz%sNc             S   s   g | ]}|  qS rX   )r   )rd   r  rX   rX   rY   rf   )  s    z6EnvironmentDescription.get_version.<locals>.<listcomp>ro   )r   r   r   r   r  )rg   r  r   r   r   rX   rX   rY   r    s    z"EnvironmentDescription.get_versionc          	   C   s    t | }|  S Q R X dS )z5
        :type path: str
        :rtype: str
        N)r   readliner   )r`   	script_fdrX   rX   rY   r  +  s    
z"EnvironmentDescription.get_shebangc             C   s.   t j| sdS t }|t|  | S )z<
        :type path: str
        :rtype: str | None
        N)r]   r`   r   hashlibmd5r   r   	hexdigest)r`   Z	file_hashrX   rX   rY   r  4  s
    zEnvironmentDescription.get_hashN)__name__
__module____qualname____doc__r  staticmethodr  r  rk  r   r  r  r  rX   rX   rX   rY   re    s   &3
(	re  c                   s    e Zd ZdZ fddZ  ZS )r  zIException when change detection was performed, but no changes were found.c                s   t t| d d S )NzNo changes detected.)superr  r  )r  )	__class__rX   rY   r  F  s    zNoChangesDetected.__init__)r  r  r  r  r  __classcell__rX   rX   )r  rY   r  D  s   r  c                   s    e Zd ZdZ fddZ  ZS )r  zBException when changes detected, but no tests trigger as a result.c                s   t t| d d S )Nz$No tests found for detected changes.)r  r  r  )r  )r  rX   rY   r  L  s    zNoTestsForChanges.__init__)r  r  r  r  r  r  rX   rX   )r  rY   r  J  s   r  c                   s"   e Zd ZdZd fdd	Z  ZS )r   zTrigger command delegation.Nc                s2   t t|   |pg | _|pg | _|p*t | _dS )z
        :type exclude: list[str] | None
        :type require: list[str] | None
        :type integration_targets: tuple[IntegrationTarget] | None
        N)r  r   r  rA  rG  ru   rH  )r  rA  rG  rH  )r  rX   rY   r  R  s    

zDelegate.__init__)NNN)r  r  r  r  r  r  rX   rX   )r  rY   r   P  s   r   c                   s    e Zd ZdZ fddZ  ZS )rK  zAll targets skipped.c                s   t t| d d S )NzAll targets skipped.)r  rK  r  )r  )r  rX   rY   r  a  s    zAllTargetsSkipped.__init__)r  r  r  r  r  r  rX   rX   )r  rY   rK  _  s   rK  )NNF)F)NNTN)N)NNN)N)N)N)r  
__future__r   r   r   rX  __metaclass__rq   r]   rt  rv   r   r	  r   r  r  r  rQ  rS  rp  ro   r   tthreadr   r   r   r	   Z	manage_cir
   r   Zcloudr   r   r   r   r   ior   r   r   r   r   utilr   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   Zutil_commonr*   r+   r,   r-   r.   r/   r0   r1   r2   r3   Zdocker_utilr4   r5   r6   r7   r8   r9   r:   r;   r<   Zansible_utilr=   r>   r   r?   r@   rA   rB   rC   rD   cirE   ZclassificationrF   r   rG   rH   rI   rJ   rK   rL   rM   rN   r   rO   r   rP   rQ   rR   rS   rT   rU   r  rV   r  rZ   rW   ri   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r5  r)  r6  r*  r+  r   r   r.  r  r   rf  r  rh  ri  rI  r  rJ  r  r  r  r  r  r  r  re  r  r  rl  r   rK  rX   rX   rX   rY   <module>   s   X0, 	( 	$
i


AJ#- A
; 
 I+
:*
-
gM" % <