o
    9A_T2  ã                   @   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 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ ddlmZmZ ddlmZ ddlmZmZ ddl Z e j!dksye j!j"dkr~ddl#Z#nddlm#Z# e j!dkr™e j$dkr™ddl%Z%e% &e% '¡ ¡ e (d¡Z)dZ*dd„ Z+d#dd„Z,G dd„ dej-ƒZ.G dd „ d eƒZ/G d!d"„ d"e0ƒZ1dS )$z¶
    livereload.server
    ~~~~~~~~~~~~~~~~~

    WSGI app server for livereload.

    :copyright: (c) 2013 - 2015 by Hsiaoming Yang
    :license: BSD, see LICENSE for more details.
é    N)ÚPopenÚPIPE)ÚWSGIContainer)ÚIOLoop)Úadd_reload_hook)Úweb)Úescape)Úhttputil)ÚLogFormatteré   )ÚLiveReloadHandlerÚLiveReloadJSHandler)ÚForceReloadHandlerÚStaticFileHandler)Úget_watcher_class)Ústring_typesÚPY3)é   é   é   )Úerrno)r   é   Úwin32Ú
livereloads   </head>c                    s   ‡ ‡‡fdd„}|S )z1Helper Function to Add HTTP headers to the serverc                    s&   ˆ | g|¢R i |¤Ž |   ˆˆ¡ d S ©N)Ú
set_header)ÚselfÚargsÚkwargs©ÚfnÚnameÚvalue© ú3/usr/lib/python3/dist-packages/livereload/server.pyÚset_default_headers2   s   z'set_header.<locals>.set_default_headersr#   )r    r!   r"   r%   r#   r   r$   r   0   s   r   ÚwFc                    sf   ˆst j‰nt j ˆ¡}|rt j |¡st  |¡ tˆ ttfƒs'ˆs't	 
ˆ ¡‰ ‡ ‡‡‡‡fdd„}|S )aA  Execute a shell command.

    You can add a shell command::

        server.watch(
            'style.less', shell('lessc style.less', output='style.css')
        )

    :param cmd: a shell command, string or list
    :param output: output stdout to the given file
    :param mode: only works with output, mode ``w`` means write,
                 mode ``a`` means append
    :param cwd: set working directory before command is executed.
    :param shell: if true, on Unix the executable argument specifies a
                  replacement shell for the default ``/bin/sh``.
    c               
      sÌ   zt ˆ tttˆˆd�} W n' ty3 } zt |¡ |jtjkr't dˆ d ¡ |W  Y d }~S d }~ww |  ¡ \}}|rCt |¡ |S trI| 	¡ }t
ˆˆƒ�}| |¡ W d   ƒ d S 1 s_w   Y  d S )N)ÚstdinÚstdoutÚstderrÚcwdÚshellzmaybe you haven't installed %sr   )r   r   ÚOSErrorÚloggerÚerrorr   ÚENOENTÚcommunicater   ÚdecodeÚopenÚwrite)ÚpÚer(   r)   Úf©Úcmdr*   ÚmodeÚoutputr+   r#   r$   Ú	run_shellS   s(   
ÿ
€ü
"ÿzshell.<locals>.run_shell)ÚosÚdevnullÚpathÚdirnameÚisdirÚmakedirsÚ
isinstanceÚlistÚtupleÚshlexÚsplit)r8   r:   r9   r*   r+   Úfolderr;   r#   r7   r$   r+   8   s   

r+   c                       s$   e Zd Z‡ fdd„Zdd„ Z‡  ZS )ÚLiveScriptInjectorc                    s   t t| ƒ |¡ d S r   )ÚsuperrH   Ú__init__)r   Úrequest©Ú	__class__r#   r$   rJ   j   s   zLiveScriptInjector.__init__c                 C   sN   t |v r"| t | jt  ¡}d|v r"t|d ƒt| jƒ }t|ƒ|d< |||fS )NúContent-Length)ÚHEAD_ENDÚreplaceÚscriptÚintÚlenÚstr)r   Ústatus_codeÚheadersÚchunkÚ	finishingÚlengthr#   r#   r$   Útransform_first_chunkm   s   
z(LiveScriptInjector.transform_first_chunk)Ú__name__Ú
__module__Ú__qualname__rJ   rZ   Ú__classcell__r#   r#   rL   r$   rH   i   s    rH   c                   @   s   e Zd Zddd„Zdd„ ZdS )ÚLiveScriptContainerÚ c                 C   s   || _ || _d S r   )Úwsgi_apprQ   )r   ra   rQ   r#   r#   r$   rJ   w   s   
zLiveScriptContainer.__init__c              	      s�  i ‰ g ‰d‡ ‡fdd„	}|   t |¡|¡}zˆ |¡ d ˆ¡}W t|dƒr*| ¡  nt|dƒr5| ¡  w w ˆ s<tdƒ‚ˆ d  dd¡\}}t	|ƒ}ˆ d	 }t
d
d„ |D ƒƒ}t |¡}t|v ri| t| jt ¡}|dkr…d|vrv| d¡ d|vr…| dtt|ƒƒf¡ d|vrŽ| d¡ t d||¡}	t ¡ }
|D ]\}}| ¡ dkr«tt|ƒƒ}|
 ||¡ q›|jj|	|
|d� |j ¡  |  ||¡ d S )Nc                    s   | ˆ d< |ˆ d< ˆj S )NÚstatusrV   )Úappend)rb   Úresponse_headersÚexc_info©ÚdataÚresponser#   r$   Ústart_response   s   z4LiveScriptContainer.__call__.<locals>.start_responseó    Úclosez$WSGI app did not call start_responserb   ú r   rV   c                 s   s   � | ]	\}}|  ¡ V  qd S r   )Úlower)Ú.0ÚkÚvr#   r#   r$   Ú	<genexpr>’   s   € z/LiveScriptContainer.__call__.<locals>.<genexpr>i0  zcontent-type)zContent-Typez'application/octet-stream; charset=UTF-8zcontent-lengthrN   Úserver)ÚServerÚ
LiveServerzHTTP/1.1)rW   r   )ra   r   ÚenvironÚextendÚjoinÚhasattrrk   Ú	ExceptionrF   rR   Úsetr   Úutf8rO   rP   rQ   rc   rT   rS   r	   ÚResponseStartLineÚHTTPHeadersrm   ÚaddÚ
connectionÚwrite_headersÚfinishÚ_log)r   rK   ri   Úapp_responseÚbodyrU   ÚreasonrV   Ú
header_setÚ
start_lineÚ
header_objÚkeyr"   r#   rf   r$   Ú__call__{   sT   
ÿ

€
ÿ
ÿ


ÿ
zLiveScriptContainer.__call__N)r`   )r[   r\   r]   rJ   rŠ   r#   r#   r#   r$   r_   v   s    
r_   c                   @   sZ   e Zd ZdZddd„Zdd„ Zddd„Z			dd
d„Zdd„ Z			ddd„Z	dd„ Z
dS )rs   a¯  Livereload server interface.

    Initialize a server and watch file changes::

        server = Server(wsgi_app)
        server.serve()

    :param app: a wsgi application instance
    :param watcher: A Watcher instance, you don't have to initialize
                    it by yourself. Under Linux, you will want to install
                    pyinotify and use INotifyWatcher() to avoid wasted
                    CPU usage.
    Nc                 C   s,   d | _ || _|stƒ }|ƒ }|| _t| _d S r   )ÚrootÚappr   Úwatcherr   ÚSFH)r   rŒ   r�   Úwatcher_clsr#   r#   r$   rJ   ¿   s   
zServer.__init__c                 C   s   t tj||ƒt_t| _dS )aï  Add or override HTTP headers at the at the beginning of the 
           request.

        Once you have intialized a server, you can add one or more 
        headers before starting the server::

            server.setHeader('Access-Control-Allow-Origin', '*')
            server.setHeader('Access-Control-Allow-Methods', '*')
            server.serve()

        :param name: The name of the header field to be defined.
        :param value: The value of the header field to be defined.
        N)r   r   r%   rŽ   )r   r!   r"   r#   r#   r$   Ú	setHeaderÉ   s   ÿ
zServer.setHeaderc                 C   s:   t |tƒr|}t|ƒ}d |¡|_| jj||||d� dS )a¸  Add the given filepath for watcher list.

        Once you have intialized a server, watch file changes before
        serve the server::

            server.watch('static/*.stylus', 'make static')
            def alert():
                print('foo')
            server.watch('foo.txt', alert)
            server.serve()

        :param filepath: files to be watched, it can be a filepath,
                         a directory, or a glob pattern
        :param func: the function to be called, it can be a string of
                     shell command, or any callable object without
                     parameters
        :param delay: Delay sending the reload message. Use 'forever' to
                      not send it. This is useful to compile sass files to
                      css, but reload on changed css files then only.
        :param ignore: A function return True to ignore a certain pattern of
                       filepath.
        z	shell: {})ÚignoreN)rB   r   r+   Úformatr!   r�   Úwatch)r   ÚfilepathÚfuncÚdelayr‘   r8   r#   r#   r$   r“   Û   s
   
zServer.watchTc                    sê   | j t_ |t_|d u r| jrd}dtfdtfdtfg}d‰ |r't ˆ | ¡‰ nt ˆ d ¡‰ |  ˆ ¡}G ‡ fdd„dt	ƒ}|sU|| }	t
j|	||gd	�}
|
j||d
� d S t
j|||gd	�}
|
j||d
� t
j|dd�}|j||d
� d S )NTz/livereloadz/forcereloadz/livereload.jszÕ<script type="text/javascript">(function(){var s=document.createElement("script");var port=%s;s.src="//"+window.location.hostname+":"+port+ "/livereload.js?port=" + port;document.head.appendChild(s);})();</script>zJ(window.location.port || (window.location.protocol == 'https:' ? 443: 80))c                       s   e Zd Z” ZdS )z/Server.application.<locals>.ConfiguredTransformN)r[   r\   r]   rQ   r#   ©Úlive_scriptr#   r$   ÚConfiguredTransform  s    r™   )ÚhandlersÚdebugÚ
transforms)ÚaddressF)rš   r›   )r�   r   Úlive_cssrŒ   r   r   r   r{   Úget_web_handlersrH   r   ÚApplicationÚlisten)r   ÚportÚhostÚliveportr›   rž   Úlive_handlersÚweb_handlersr™   rš   rŒ   Úliver#   r—   r$   Úapplicationù   s>   ý
ÿ	
ýýzServer.applicationc                 C   s@   | j rt| j |ƒ}dtjd|ifgS d| j| jpd| jdœfgS )Nz.*Úfallbackz/(.*)Ú.)r>   Údefault_filename)rŒ   r_   r   ÚFallbackHandlerrŽ   r‹   r«   )r   rQ   r©   r#   r#   r$   rŸ   .  s   þÿzServer.get_web_handlersé|  Fr   ú
index.htmlc                    sØ   ˆ pd‰ |dur|| _ |  ¡  t dˆ ˆf ¡ |
| _| jˆˆ |||	d� |r,t d¡ ˆdur@‡ ‡‡fdd„}tj|d� 	¡  z| j
j d	|f¡ t ¡  td
d„ ƒ t ¡  	¡  W dS  tyk   t d¡ Y dS w )a  Start serve the server with the given port.

        :param port: serve on this port, default is 5500
        :param liveport: live reload on this port
        :param host: serve on this hostname, default is 127.0.0.1
        :param root: serve static on this root directory
        :param debug: set debug mode, which autoreloads the app on code changes
                      via Tornado (and causes polling). Defaults to True when
                      ``self.app`` is set, otherwise False.
        :param open_url_delay: open webbrowser after the delay seconds
        :param live_css: whether to use live css or force reload on css.
                         Defaults to True
        :param default_filename: launch this file from the selected root on startup
        z	127.0.0.1NzServing on http://%s:%s)r¤   r›   rž   z*Use `open_url_delay` instead of `open_url`c                      s    t  ˆ¡ t dˆ ˆf ¡ d S )Nzhttp://%s:%s)ÚtimeÚsleepÚ
webbrowserr2   r#   ©r£   Úopen_url_delayr¢   r#   r$   Úopener[  s   
zServer.serve.<locals>.opener)ÚtargetÚ__livereload__c                   S   s   t  ¡ jdd�S )NT)Úall_fds)r   Úinstancerk   r#   r#   r#   r$   Ú<lambda>c  s    zServer.serve.<locals>.<lambda>zShutting down...)r‹   Ú_setup_loggingr-   Úinfor«   r¨   r.   Ú	threadingÚThreadÚstartr�   Ú_changesrc   r   Ústart_tasksr   r   r¸   ÚKeyboardInterrupt)r   r¢   r¤   r£   r‹   r›   Úopen_urlÚrestart_delayr³   rž   r«   r´   r#   r²   r$   Úserve9  s,   
ÿ
ÿzServer.servec                 C   s>   t  tj¡ t ¡ }| tƒ ¡ t  |¡ t d¡ |¡ d S )NÚtornado)	r-   ÚsetLevelÚloggingÚINFOÚStreamHandlerÚsetFormatterr
   Ú
addHandlerÚ	getLogger)r   Úchannelr#   r#   r$   rº   h  s
   
zServer._setup_logging)NN)NNN)NNT)
r­   NNNNFr   NTr®   )r[   r\   r]   Ú__doc__rJ   r�   r“   r¨   rŸ   rÄ   rº   r#   r#   r#   r$   rs   ±   s    



ÿ5
þ/rs   )Nr&   NF)2rÎ   r<   r¯   rE   rÇ   r¼   r±   Ú
subprocessr   r   Útornado.wsgir   Útornado.ioloopr   Útornado.autoreloadr   rÅ   r   r   r	   Útornado.logr
   rš   r   r   r   r   r�   r   Úsixr   r   ÚsysÚversion_infoÚmajorr   ÚplatformÚasyncioÚset_event_loop_policyÚWindowsSelectorEventLoopPolicyrÌ   r-   rO   r   r+   ÚOutputTransformrH   r_   Úobjectrs   r#   r#   r#   r$   Ú<module>   sB   



1;