B
    nôb\i$  ã               @   s
  d Z eZddlZddlZddlmZ ddlZddlm	Z	 ddl
mZmZ dd„ ZddlmZ ejd	ksœdd
lmZ ddlmZ ddlmZ ddlmZ dZnLdZddlZddlmZ dZdZdd„ Zdd„ ZeZdd„ Zdd„ Zdd„ ZG dd„ dƒZdd „ Zdd gZdS )!aŽ  
Filesystem-based interprocess mutex.

Taken from the Twisted project.
Distributed under the MIT (Expat) license.

Changes by the Spyder Team to the original module:
  * Rewrite kill Windows function to make it more reliable.
  * Detect if the process that owns the lock is an Spyder one.

Adapted from src/twisted/python/lockfile.py of the
`Twisted project <https://github.com/twisted/twisted>`_.
é    N)Útime)Úrunning_under_pytest)ÚPY2Úto_binary_stringc               C   s,   t rtttƒ d ƒƒS tttƒ d ƒƒS d S )Niè  )r   ÚstrZlongÚ_uniquefloatÚint© r	   r	   ú=lib/python3.7/site-packages/spyder/utils/external/lockfile.pyÚunique"   s    r   )ÚrenameÚnt)Úkill)Úsymlink)Úreadlink)ÚremoveFT)Úwintypesi   i  c             C   s\   t jj}| td| ¡}|dkr"dS t ¡ }| |t  |¡¡}|dk}| 	|¡ |pZ|j
tkS )z/Taken from https://www.madebuild.org/blog/?p=30r   F)ÚctypesZwindllÚkernel32ZOpenProcessÚPROCESS_QUERY_INFORMATIONr   ZDWORDZGetExitCodeProcessZbyrefZCloseHandleÚvalueÚSTILL_ACTIVE)Úpidr   ZhandleZ	exit_codeZretvalZ
is_runningr	   r	   r
   Ú_is_pid_running<   s    
r   c             C   s   t | ƒsttjd ƒ‚nd S d S )N)r   ÚOSErrorÚerrnoÚESRCH)r   Úsignalr	   r	   r
   r   O   s    r   c             C   s¦   |d t ƒ  d }tj |d¡}t |¡ t|dƒ}| t| ƒ¡ | ¡  | 	¡  yt
||ƒ W n@   yt |¡ t |¡ W n ttfk
r˜   Y nX ‚ Y nX d S )NÚ.z.newlinkr   Úwb)r   ÚosÚpathÚjoinÚmkdirÚ_openÚwriter   ÚflushÚcloser   r   ÚrmdirÚIOErrorr   )r   ÚfilenameZnewlinknameZ
newvalnameÚfr	   r	   r
   r   X   s     


r   c          
   C   s~   yt tj | d¡dƒ}W nH tk
r` } z*|jtjksB|jtjkrNt|jd ƒ‚‚ W d d }~X Y nX | 	¡  
¡ }| ¡  |S d S )Nr   Úrb)r$   r    r!   r"   r)   r   ÚENOENTÚEIOr   ÚreadÚdecoder'   )r*   ZfObjÚeÚresultr	   r	   r
   r   j   s    r   c             C   s"   t  t j | d¡¡ t  | ¡ d S )Nr   )r    r   r!   r"   r(   )r*   r	   r	   r
   Úrmlinkv   s    r3   c               @   s0   e Zd ZdZdZdZdd„ Zdd„ Zdd	„ ZdS )
ÚFilesystemLocka  
    A mutex.

    This relies on the filesystem property that creating
    a symlink is an atomic operation and that it will
    fail if the symlink already exists.  Deleting the
    symlink will release the lock.

    @ivar name: The name of the file associated with this lock.

    @ivar clean: Indicates whether this lock was released cleanly by its
        last owner.  Only meaningful after C{lock} has been called and
        returns True.

    @ivar locked: Indicates whether the lock is currently held by this
        object.
    NFc             C   s
   || _ d S )N)Úname)Úselfr5   r	   r	   r
   Ú__init__’   s    zFilesystemLock.__init__c             C   s  d}xyt tt ¡ ƒ| jƒ W nÚ tk
rü } z¸trR|jtjtj	fkrRdS |jtj
krêyt| jƒ}W nh tk
r  } z|jtjkrŽw‚ W dd}~X Y n8 tk
rÖ } ztrÄ|jtjkrÄdS ‚ W dd}~X Y nX yŒtdk	rðtt|ƒdƒ t t|ƒ¡}tddddd	d
gƒ}tƒ r$| d¡ tdd„ | ¡ dd… D ƒƒ}||@ g}t|ƒsbttjdƒ‚W n€ tk
rä } z`|jtjkrÒyt| jƒ W n6 tk
rÊ } z|jtjkr¸w‚ W dd}~X Y nX d}w‚ W dd}~X Y nX dS ‚ W dd}~X Y nX d| _|| _dS dS )zÏ
        Acquire this lock.

        @rtype: C{bool}
        @return: True if the lock is acquired, false otherwise.

        @raise: Any exception os.symlink() may raise, other than
        EEXIST.
        TFNr   ZspyderZspyder3z
spyder.exezspyder3.exezbootstrap.pyzspyder-script.pyzruntests.pyc             s   s   | ]}t j |¡V  qd S )N)r    r!   Úbasename)Ú.0Úargr	   r	   r
   ú	<genexpr>Ê   s   z&FilesystemLock.lock.<locals>.<genexpr>é   zNo such process)r   r   r    Úgetpidr5   r   Ú_windowsr   ZEACCESr.   ZEEXISTr   r-   r)   r   r   ÚpsutilZProcessÚsetr   ÚaddZcmdlineÚanyr   r3   ÚlockedÚclean)r6   rD   r1   r   ÚpÚnamesZ	argumentsZ
conditionsr	   r	   r
   Úlock•   s`    



zFilesystemLock.lockc             C   s>   t | jƒ}t|ƒt ¡ kr*td| jf ƒ‚t| jƒ d| _dS )zÕ
        Release this lock.

        This deletes the directory with the given name.

        @raise: Any exception os.readlink() may raise, or
        ValueError if the lock is not owned by this process.
        z!Lock %r not owned by this processFN)r   r5   r   r    r=   Ú
ValueErrorr3   rC   )r6   r   r	   r	   r
   Úunlockå   s
    	

zFilesystemLock.unlock)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__rD   rC   r7   rG   rI   r	   r	   r	   r
   r4   |   s   Pr4   c             C   s.   t | ƒ}d}z| ¡ }W d|r&| ¡  X | S )zÚDetermine if the lock of the given name is held or not.

    @type name: C{str}
    @param name: The filesystem path to the lock to test

    @rtype: C{bool}
    @return: True if the lock is held, False otherwise.
    N)r4   rG   rI   )r5   Úlr2   r	   r	   r
   ÚisLockedõ   s    	
rO   ) rM   ÚtypeZ__metaclass__r   r    r   r   r?   Zspyder.config.baser   Zspyder.py3compatr   r   r   r   r5   r   r   r   r   r3   r>   r   r   r   r   r   Úopenr$   r4   rO   Ú__all__r	   r	   r	   r
   Ú<module>   s8   
y