B
    |?Xc-@                 @   s   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m	Z	m
Z
mZmZmZm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 ZG dd	 d	ZG d
d dejZe
e ee ee dddZG dd dZdd ZdS )    N)Path)ListUnionSequenceOptionalAnyTupleSet)Producer)	_sys_pathc          	   C   s   g }xl|  dD ]^}|d}yt|d | }W n tk
rP   || Y qX |||d d  g|  qW |std|S )NZtx*   z6MISSING test execution (tx) nodes: please specify --tx)getvaluefindint
ValueErrorappendextendpytest
UsageError)configZ	xspeclistZxspeciZnum r   1lib/python3.7/site-packages/xdist/workermanage.pyparse_spec_config   s    
 r   c               @   sx   e Zd ZdZddddgZdddd	d
Zdd Zdd Zdd Zdd Z	dd Z
ee dddZdd ZdddZdS )NodeManager
   z.*z*.pycz*.pyoz*~Npyexecnetcache)returnc             C   s   || _ | j jd| _| j d| _| jd kr:t j| _t	 | _
|d krT|  }g | _xL|D ]D}t|tjszt|}|js|js||_| j
| | j| q`W |  | _|  | _t | _d S )Nnodemanager
testrunuid)r   tracegetZ	getoptionr    uuidZuuid4hexexecnetZGroupgroup
_getxspecsspecs
isinstanceXSpecchdirpopenZallocate_idr   _getrsyncdirsroots_getrsyncoptionsrsyncoptionsset_rsynced_specs)selfr   r(   Zdefaultchdirspecr   r   r   __init__&   s&    





zNodeManager.__init__c             C   s,   | j r(x | j D ]}| j||f| j qW dS )z1Rsync the set of roots to the node's gateway cwd.N)r.   rsyncr0   )r3   gatewayrootr   r   r   rsync_roots;   s    zNodeManager.rsync_rootsc                s6   j jjj jd d  fddjD S )N)r   r(   zsetting up nodesc                s   g | ]} | qS r   )
setup_node).0r4   )puteventr3   r   r   
<listcomp>D   s    z+NodeManager.setup_nodes.<locals>.<listcomp>)r   hookZpytest_xdist_setupnodesr(   r!   )r3   r<   r   )r<   r3   r   setup_nodesA   s    
zNodeManager.setup_nodesc             C   sV   | j |}| jjj|d | | t| || j|}||_|  | 	d|  |S )N)r7   zstarted node %r)
r&   Zmakegatewayr   r>   Zpytest_xdist_newgatewayr9   WorkerControllernodesetupr!   )r3   r4   r<   ZgwrA   r   r   r   r:   F   s    
zNodeManager.setup_nodec             C   s   | j | j d S )N)r&   Z	terminateEXIT_TIMEOUT)r3   r   r   r   teardown_nodesP   s    zNodeManager.teardown_nodesc             C   s   dd t | jD S )Nc             S   s   g | ]}t |qS r   )r%   r*   )r;   xr   r   r   r=   T   s    z*NodeManager._getxspecs.<locals>.<listcomp>)r   r   )r3   r   r   r   r'   S   s    zNodeManager._getxspecsc             C   s   x | j D ]}|jr|jrP qW g S dd l}dd l}dd }||j}||j}| j}||g}||jj7 }|	d}	|	r|
|	 g }
xB|D ]:}t| }| s|d|||
kr|
| qW |
S )Nr   c             S   s.   |  d}tj|dkr&tj| S |S dS )zRReturn the directory path if p is a package or the path to the .py file otherwise.coz__init__.pyN)rstripospathbasenamedirname)pstrippedr   r   r   get_dir_   s    
z*NodeManager._getrsyncdirs.<locals>.get_dirZ	rsyncdirszrsyncdir doesn't exist: {!r})r(   r,   r+   r   _pytest__file__r   optionZrsyncdirgetinir   r   Zresolveexistsr   formatr   )r3   r4   r   rO   rN   Z
pytestpathZ	pytestdirr   Z
candidatesZ
rsyncrootsr.   r8   r   r   r   r-   V   s.    




zNodeManager._getrsyncdirsc             C   sR   t | j}|dd | jjjD 7 }|dd | jdD 7 }|t| jjdddS )z#Get options to be passed for rsync.c             S   s   g | ]}t |qS r   )str)r;   rI   r   r   r   r=   {   s    z0NodeManager._getrsyncoptions.<locals>.<listcomp>c             S   s   g | ]}t |qS r   )rU   )r;   rI   r   r   r   r=   |   s    rsyncignoreverboser   )ignoresrW   )listDEFAULT_IGNORESr   rQ   rV   rR   getattr)r3   rX   r   r   r   r/   x   s
    
zNodeManager._getrsyncoptionsFc                s   t ||d}|jjrBjsB|dtjt 	  dS f| j
krTdS  fdd}|j||d | j
f | jjj|gd |  | jjj|gd dS )z'Perform rsync to remote hosts for node.)rW   rX   zA
                import sys ; sys.path.insert(0, %r)
            Nc                  s    r d d S )NZrsyncrootreadyr   r   )notifysourcer4   r   r   finished   s    z#NodeManager.rsync.<locals>.finished)r^   )r]   Zgateways)	HostRSyncr4   r,   r+   remote_execrH   rI   rK   rU   Z	waitcloser2   add_target_hostaddr   r>   Zpytest_xdist_rsyncstartsendZpytest_xdist_rsyncfinish)r3   r7   r]   r\   rW   rX   r6   r^   r   )r\   r]   r4   r   r6      s    zNodeManager.rsync)Nr   )NFN)__name__
__module____qualname__rC   rZ   r5   r9   r?   r:   rD   r'   r   r   r-   r/   r6   r   r   r   r   r   "   s   
"r   c                   sl   e Zd ZdZeedf Zddeeee  e	dd fddZ
eedd	d
Zd fdd	Zdd Z  ZS )r_   z%RSyncer that filters out common fileszos.PathLike[str]N)rX   )	sourcedirrX   kwargsr   c               s:   |d krg }dd |D | _ t jf dt|i| d S )Nc          	   S   s"   g | ]}t tt|qS r   )recompilefnmatch	translaterH   fspath)r;   rE   r   r   r   r=      s    z&HostRSync.__init__.<locals>.<listcomp>rg   )_ignoressuperr5   r   )r3   rg   rX   rh   )	__class__r   r   r5      s    zHostRSync.__init__)rI   r   c             C   s>   t |}x0| jD ]"}||js.|t|rdS qW dS d S )NFT)r   rn   matchnamerU   )r3   rI   Zcrer   r   r   filter   s
    zHostRSync.filterc                s&   t j| j}t j|||dd d S )NT)Zfinishedcallbackdelete)rH   rI   rJ   
_sourcedirro   Z
add_target)r3   r7   r^   
remotepath)rp   r   r   ra      s    zHostRSync.add_target_hostc             C   s@   | j dkr<tj| jd | }|jj}td|j|| d S )Nr   /z{}:{} <= {})	Z_verboserH   rI   rJ   ru   r4   r+   printrT   )r3   r7   Zmodified_rel_pathrI   rv   r   r   r   _report_send_file   s    
zHostRSync._report_send_file)N)rd   re   rf   __doc__r   rU   PathLiker   r   objectr5   boolrs   ra   ry   __classcell__r   r   )rp   r   r_      s   r_   )r.   argsr   c       
   
   C   s   d}g }x|D ]}| |}t|d }y| }W n tk
rL   d}Y nX |s^|| qxf| D ]P}y||}	W n tk
r   d }	Y nX |	s||krd|jd t|	 |d< P qdW td	|||
| qW |S )Nz::r   Frw   z$arg {} not relative to an rsync root)splitr   rS   OSErrorr   Zrelative_tor   rr   rU   rT   join)
r.   r   Z	splitcoderesultargpartsrm   rS   r8   rE   r   r   r   make_reltoroot   s.    





r   c               @   sz   e Zd ZdZG dd dZdd Z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S )r@   c               @   s    e Zd Zejdddd ZdS )zWorkerController.RemoteHookT)Ztrylastc             C   s   t jS )N)xdistZremote)r3   r   r   r   pytest_xdist_getremotemodule   s    z8WorkerController.RemoteHook.pytest_xdist_getremotemoduleN)rd   re   rf   r   Zhookimplr   r   r   r   r   
RemoteHook   s   r   c             C   sn   |j |   || _|| _|| _|| _|jt|j	|j
tjd| _d| _d| _td|j |jjd| _d S )N)ZworkeridZworkercountr    ZmainargvFz
workerctl-)Zenabled)Zpluginmanagerregisterr   r   r<   r7   r   idlenr(   r    sysargvworkerinput_down_shutdown_sentr
   rQ   debuglog)r3   r   r7   r   r<   r   r   r   r5      s    zWorkerController.__init__c             C   s   d | jj| jjS )Nz<{} {}>)rT   rp   rd   r7   r   )r3   r   r   r   __repr__   s    zWorkerController.__repr__c             C   s   | j p
| jS )N)r   r   )r3   r   r   r   shutting_down   s    zWorkerController.shutting_downc             C   s  |  d | jj}t| jdr<dd | jjjp0dD }i }n| jj}t| jj}|j	r\|j
rjt| jj|}|j	rd| jj }t| jdr| jj }t|| |d< | jjj| d	 | jj }| j|| _| jjj	rtnd }| j| j|||f | jr| jj| j| jd
 d S )Nzsetting up worker sessioninvocation_paramsc             S   s   g | ]}t |qS r   )rU   )r;   rE   r   r   r   r=     s    z*WorkerController.setup.<locals>.<listcomp>r   zpopen-%s_tmp_path_factorybasetemp)rA   )Z	endmarker)r   r7   r4   hasattrr   r   r   varsrQ   r,   r+   r   r   r.   r   r   ZgetbasetemprU   r>   Zpytest_configure_noder   r`   channelr   rc   r   r<   Zsetcallbackprocess_from_remoteENDMARK)r3   r4   r   Zoption_dictrr   r   Zremote_moduleZchange_sys_pathr   r   r   rB     s*    
zWorkerController.setupc             C   sR   t | dr,| j s,| d| j | j  t | drN| d| j | j  d S )Nr   closingr7   Zexiting)r   r   Zisclosedr   closer7   exit)r3   r   r   r   ensure_teardown  s    



z WorkerController.ensure_teardownc             C   s   | j d|d d S )NZruntests)indices)sendcommand)r3   r   r   r   r   send_runtest_some)  s    z"WorkerController.send_runtest_somec             C   s   |  d d S )NZruntests_all)r   )r3   r   r   r   send_runtest_all,  s    z!WorkerController.send_runtest_allc             C   s4   | j s0y| d W n tk
r(   Y nX d| _d S )NshutdownT)r   r   r   r   )r3   r   r   r   r   /  s    zWorkerController.shutdownc             K   s&   |  d|| | j||f dS )z4send a named parametrized command to the other side.zsending command {}(**{})N)r   rT   r   rc   )r3   rr   rh   r   r   r   r   7  s    zWorkerController.sendcommandc             K   s$   |  d|| | ||f d S )Nzqueuing {}(**{}))r   rT   r<   )r3   	eventnamerh   r   r   r   notify_inproc<  s    zWorkerController.notify_inprocc       
      C   s  y<|| j krJ| j }| jsF|r,t|tr0d}| jd| |d d| _dS |\}}|dkrp| d|| n|dkr| j|fd	| i| n|d
kr| j|fd	| i| n|dkrd| _|d | _	| jd| d n^|dkr| j|fd	| i| n:|dkrR|
dd}| jjj| j|d d}|dk	r@||_| j|| |d n|dkrr| j|| |d d n|dkr| j|fd	| i| n|dkr| j||d |d |d |d d nx|dkrt|d }| j|||d |d  d! nF|d"kr.t|d }| j|||d |d |d# d$ ntd%|W nd tk
rV    Y nN   d&d'lm} | }	td(|	 | j|	 |   | jd| |	d Y nX dS ))a
  this gets called for each object we receive from
        the other side and if the channel closes.

        Note that channel callbacks run in the receiver
        thread of execnet gateways - we need to
        avoid raising exceptions or doing heavy work.
        zNot properly terminatedZ	errordown)rA   errorTN)Zcollectionstartzignoring {}({})ZworkerreadyrA   Zinternal_errorZworkerfinishedworkeroutput)rA   )ZlogstartZ	logfinish)Z
testreportZcollectreportZteardownreport
item_indexdata)r   r   )rA   repZcollectionfinishids)rA   r   Zruntest_protocol_completeZ
logwarningmessagecodenodeid)r   r   r   Z
fslocationZwarning_capturedZwarning_message_datawhenitem)warning_messager   r   Zwarning_recordedlocation)r   r   r   r   zunknown event: {}r   )ExceptionInfoz!!!!!!!!!!!!!!!!!!!!)r   r   Z_getremoteerrorr   r)   EOFErrorr   r   rT   r   popr   r>   Zpytest_report_from_serializabler   unserialize_warning_messager   KeyboardInterruptZ_pytest._coder   Zfrom_currentrx   Znotify_exceptionr   )
r3   Z	eventcallerrr   rh   r   r   r   r   excinfor   r   r   r   @  s    













z$WorkerController.process_from_remoteN)rd   re   rf   r   r   r5   r   propertyr   rB   r   r   r   r   r   r   r   r   r   r   r   r@      s   r@   c       
      C   s  dd l }dd l}| d r|| d }t|| d }d }| d d k	rjy|| d  }W n tk
rh   Y nX |d krdj| d | d | d d}t|}n| d }| d r|| d }t|| d	 }nd }||d
}x&|jjD ]}	|	d
krq| |	 ||	< qW |jf |S )Nr   Zmessage_moduleZmessage_class_nameZmessage_argsz{mod}.{cls}: {msg}Zmessage_str)modclsmsgZcategory_moduleZcategory_class_name)r   category)	warnings	importlibimport_moduler[   	TypeErrorrT   WarningWarningMessage_WARNING_DETAILS)
r   r   r   r   r   r   Zmessage_textr   rh   Z	attr_namer   r   r   r     s8    

r   )rk   rH   ri   r   r#   Zpathlibr   typingr   r   r   r   r   r   r	   r   r%   Zxdist.remoter   r
   Zxdist.pluginr   r   r   ZRSyncr_   rU   r   r@   r   r   r   r   r   <module>   s&   $ $ 4