§
    Ÿ5«j  ã                  ó&  — d Z ddlmZ ddlZddlmZ ddlZddlZddlZddl	Z	ddl
mZ  eej        d¦  «        rej                             dd¬	¦  «          eej        d¦  «        rej                             dd¬	¦  «         dd
lmZmZ ddlmZ  ee¦  «                             ¦   «         j        j        ZdZdZ ej        ¦   «         dz  dz  Zg d¢Zh d£Zh d£Zh d£Z d d„Z!d d„Z" G d„ de¦  «        Z#d!d„Z$d!d„Z%e&dk    r e%¦   «          dS dS )"a5  DSCons Real-Time "Sync on Save" Hot-Watcher daemon.

Monitors local source directories (app, deployment, docker, db, scripts, docs)
and immediately syncs modified files to the Cloud Production VM (/opt/dscons)
via OpenSSH / SCP.

Triggers Docker backend uvicorn hot-reload on the Cloud in real-time (< 0.5s).
é    )ÚannotationsN)ÚPath)ÚSetÚreconfigurezutf-8Úreplace)ÚencodingÚerrors)ÚFileSystemEventÚFileSystemEventHandler)ÚObserverÚdsconsz/opt/dsconsz.sshÚgoogle_compute_engine)ÚappÚ
deploymentÚdockerÚdbÚscriptsÚdocs>   ú	README.mdúpyproject.tomlúdocker-compose.ymlúdocker-compose.prod.ymlÚ
Dockerfile>   ú.gitú.ideaú.venvú.vscodeú.ruff_cacheúqdrant-dataÚlogsÚstorageÚdrawingsÚ	cassettesÚ__pycache__>   ú.bakú.logú.pycú.pydú.pyoú.swpú.tmpú.lockÚrel_pathr   ÚreturnÚboolc                óÂ   — t          | j        ¦  «        }|t          z  rdS | j                             ¦   «         t
          v rdS | j                             d¦  «        rdS dS )z/Check if relative path matches ignore patterns.T)ú.ú~F)ÚsetÚpartsÚIGNORE_PARTSÚsuffixÚlowerÚIGNORE_EXTENSIONSÚnameÚ
startswith)r-   r4   s     ú*C:\Projects\DSCons\scripts\sync_on_save.pyÚ
is_ignoredr<   E   sd   € å�”ÑÔ€EØ�|Ñð ØˆtØ„×ÒÑÔÕ"3Ð3Ð3ØˆtØ„}×Ò 
Ñ+Ô+ð ØˆtØˆ5ó    c                óº   — t          | ¦  «        rdS | j        r| j        d         nd}|t          v rdS t          | j        ¦  «        dk    r| j        t
          v rdS dS )z/Check if relative path is inside watched scope.Fr   Ú Té   )r<   r4   Ú
WATCH_DIRSÚlenr9   Ú
ROOT_FILES)r-   Ú
first_parts     r;   Ú
is_watchedrE   Q   sj   € å�(ÑÔð Øˆuà&.¤nÐ<�” Ô"Ð"¸"€JØ•ZÐÐØˆtÝ
ˆ8Œ>ÑÔ˜aÒÐ H¤MµZÐ$?Ð$?Øˆtàˆ5r=   c                  óJ   ‡ — e Zd Zddˆ fd„Zdd	„Zdd
„Zdd„Zdd„Zdd„Zˆ xZ	S )ÚSyncHandlerç      Ð?Údebounce_secÚfloatc                óº   •— t          ¦   «                              ¦   «          || _        i | _        t	          ¦   «         | _        t          j        ¦   «         | _        d S ©N)	ÚsuperÚ__init__rI   Ú_pendingr3   Ú_known_remote_dirsÚ	threadingÚLockÚ_lock)ÚselfrI   Ú	__class__s     €r;   rN   zSyncHandler.__init__`   sG   ø€ Ý‰Œ×ÒÑÔÐØ(ˆÔØ46ˆŒÝ,/©E¬EˆÔÝ”^Ñ%Ô%ˆŒ
ˆ
ˆ
r=   Úeventr
   r.   ÚNonec                óL   — |j         s|                      |j        ¦  «         d S d S rL   ©Úis_directoryÚ_schedule_syncÚsrc_path©rT   rV   s     r;   Úon_modifiedzSyncHandler.on_modifiedg   ó3   € ØÔ!ð 	0Ø×Ò ¤Ñ/Ô/Ð/Ð/Ð/ð	0ð 	0r=   c                óL   — |j         s|                      |j        ¦  «         d S d S rL   rY   r]   s     r;   Ú
on_createdzSyncHandler.on_createdk   r_   r=   Úfile_path_strÚstrc                óÚ  — t          |¦  «        }	 |                     t          ¦  «        }n# t          $ r Y d S w xY wt	          |¦  «        sd S |                     ¦   «         }| j        5  || j        v r| j        |                              ¦   «          t          j
        | j        | j        ||g¬¦  «        }|| j        |<   |                     ¦   «          d d d ¦  «         d S # 1 swxY w Y   d S )N)Úargs)r   Úrelative_toÚ
LOCAL_ROOTÚ
ValueErrorrE   Úas_posixrS   rO   ÚcancelrQ   ÚTimerrI   Ú_do_syncÚstart)rT   rb   Ú	file_pathr-   Ú	posix_relÚtimers         r;   r[   zSyncHandler._schedule_synco   sG  € Ý˜Ñ'Ô'ˆ	ð	Ø ×,Ò,­ZÑ8Ô8ˆHˆHøÝð 	ð 	ð 	ØˆFˆFð	øøøõ ˜(Ñ#Ô#ð 	ØˆFà×%Ò%Ñ'Ô'ˆ	ØŒZð 	ð 	Ø˜DœMÐ)Ð)Ø”˜iÔ(×/Ò/Ñ1Ô1Ð1å”OØÔ! 4¤=¸	À9Ð7Mðñ ô ˆEð (-ˆDŒM˜)Ñ$Ø�KŠK‰MŒMˆMð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   ‘, ¬
:¹:Á)A*C Ã C$Ã'C$Úparent_rel_posixc           	     ó@  — |r	|| j         v rd S t          › d|› �}ddt          t          ¦  «        ddt          d|› d�g}	 t          j        |ddd	¬
¦  «         | j                              |¦  «         d S # t          $ r }t          d|› d|› �¦  «         Y d }~d S d }~ww xY w)Nú/Ússhú-iú-oú StrictHostKeyChecking=accept-newz
mkdir -p 'ú'Té   )ÚcheckÚcapture_outputÚtimeoutz[MKDIR FAILED] ú: )
rP   ÚREMOTE_ROOTrc   ÚSSH_KEYÚREMOTE_HOSTÚ
subprocessÚrunÚaddÚ	ExceptionÚprint)rT   rq   Ú
remote_dirÚssh_cmdÚes        r;   Ú_ensure_remote_dirzSyncHandler._ensure_remote_dir„   sê   € Øð 	Ð#3°tÔ7NÐ#NÐ#NØˆFå#Ð8Ð8Ð&6Ð8Ð8ˆ
àØÝ•‰LŒLØØ.ÝØ&˜Ð&Ð&Ð&ð
ˆð	7ÝŒN˜7¨$¸tÈQÐOÑOÔOÐOØÔ#×'Ò'Ð(8Ñ9Ô9Ð9Ð9Ð9øÝð 	7ð 	7ð 	7ÝÐ5 JÐ5Ð5°!Ð5Ð5Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6øøøøð	7øøøs   ¿2A3 Á3
BÁ=BÂBÚ
local_pathr   ro   c                ó¼  — | j         5  | j                             |d ¦  «         d d d ¦  «         n# 1 swxY w Y   |                     ¦   «         sd S t	          j        ¦   «         }t          |¦  «        j                             ¦   «         }|r|dk    r|                      |¦  «         t          › dt          › d|› �}ddt          t          ¦  «        ddt          |¦  «        |g}	 t          j        |ddd	¬
¦  «        }t	          j        ¦   «         |z
  }t	          j        d¦  «        }	|j        dk    rt#          d|	› d|› d|› d|d›d�	¦  «         d S |j                             ¦   «         p|j                             ¦   «         }
t#          d|	› d|› d|
› �¦  «         d S # t*          $ r5}t#          dt	          j        d¦  «        › d|› d|› �¦  «         Y d }~d S d }~ww xY w)Nr1   ú:rs   Úscpru   rv   rw   Té
   )r{   Útextr|   z%H:%M:%Sr   ú[z] [SYNCED] z -> ú (ú.2fús)z
] [ERROR] r}   z] [EXCEPTION] )rS   rO   ÚpopÚexistsÚtimer   Úparentri   r‰   r€   r~   rc   r   r�   r‚   ÚstrftimeÚ
returncoder…   ÚstderrÚstripÚstdoutr„   )rT   rŠ   ro   Ú
start_timeÚ
parent_relÚremote_targetÚscp_cmdÚresÚelapsedÚnow_strÚerr_msgrˆ   s               r;   rl   zSyncHandler._do_sync˜   sj  € ØŒZð 	/ð 	/ØŒM×Ò˜i¨Ñ.Ô.Ð.ð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/ð × Ò Ñ"Ô"ð 	ØˆFå”Y‘[”[ˆ
Ý˜)‘_”_Ô+×4Ò4Ñ6Ô6ˆ
Øð 	0˜*¨Ò+Ð+Ø×#Ò# JÑ/Ô/Ð/å&ÐBÐB­ÐBÐB°yÐBÐBˆàØÝ•‰LŒLØØ.Ý�
‰OŒOØð
ˆð	QÝ”.ØØ#ØØð	ñ ô ˆCõ ”i‘k”k JÑ.ˆGÝ”m JÑ/Ô/ˆGØŒ~ Ò"Ð"ÝÐ]˜'Ð]Ð]¨iÐ]Ð]¸]Ð]Ð]ÈgÐ]Ð]Ð]Ð]Ñ^Ô^Ð^Ð^Ð^àœ*×*Ò*Ñ,Ô,ÐB°´
×0@Ò0@Ñ0BÔ0B�ÝÐC˜'ÐCÐC¨YÐCÐC¸'ÐCÐCÑDÔDÐDÐDÐDøÝð 	Qð 	Qð 	QÝÐO•d”m JÑ/Ô/ÐOÐO¸yÐOÐOÈAÐOÐOÑPÔPÐPÐPÐPÐPÐPÐPÐPøøøøð	Qøøøs,   ˆ0°4·4Ã$A*F ÅA
F Æ
GÆ&*GÇG)rH   )rI   rJ   )rV   r
   r.   rW   )rb   rc   r.   rW   )rq   rc   r.   rW   )rŠ   r   ro   rc   r.   rW   )
Ú__name__Ú
__module__Ú__qualname__rN   r^   ra   r[   r‰   rl   Ú__classcell__)rU   s   @r;   rG   rG   _   s®   ø€ € € € € ð&ð &ð &ð &ð &ð &ð &ð0ð 0ð 0ð 0ð0ð 0ð 0ð 0ðð ð ð ð*7ð 7ð 7ð 7ð(&Qð &Qð &Qð &Qð &Qð &Qð &Qð &Qr=   rG   rW   c                 ó’  — t          d¦  «         t          j        ¦   «         } dddt          t          ¦  «        ddt          t          dz  ¦  «        t
          › dt          › d	�g}t          j        |d
d
¬¦  «        }|j	        dk    r*t          dt          j        ¦   «         | z
  d›d�¦  «         dS t          d|j
        › �¦  «         dS )z4Perform a one-time push of all watched source files.zF>> Dang kiem tra va dong bo toan dien (Initial Sync) app/ len Cloud...r�   z-rru   rv   rw   r   rŒ   rs   T)r{   r�   r   z,[OK] Thu muc app/ da duoc dong bo hoan tat (r’   r“   z[WARN] Canh bao dong bo app/: N)r…   r–   rc   r   rg   r€   r~   r�   r‚   r™   rš   )r�   Úcmdr¡   s      r;   Úinitial_full_syncr«   Á   sÓ   € å	Ð
RÑSÔSÐSÝ”‘”€Jð 	ØØÝ�G‰ŒØØ*Ý�J˜ÑÑÔÝÐ'Ð'�Ð'Ð'Ð'ð	€Cõ Œ.˜¨T¸Ð
=Ñ
=Ô
=€CØ
„~˜ÒÐÝÐ]½T¼Y¹[¼[È:Ñ=UÐ]Ð]Ð]Ð]Ñ^Ô^Ð^Ð^Ð^åÐ;¨s¬zÐ;Ð;Ñ<Ô<Ð<Ð<Ð<r=   c                 óz  — t          j        d¬¦  «        } |                      ddd¬¦  «         |                      ¦   «         }t	          d¦  «         t	          d¦  «         t	          d	t
          › �¦  «         t	          d
t          › dt          › d�¦  «         t	          dd                     t          ¦  «        › �¦  «         t	          d¦  «         |j
        rt          ¦   «          t          ¦   «         }t          ¦   «         }|                     |t          t
          ¦  «        d¬¦  «         |                     ¦   «          t	          d¦  «         t	          d¦  «         	 	 t#          j        d¦  «         Œ# t&          $ r& t	          d¦  «         |                     ¦   «          Y nw xY w|                     ¦   «          d S )NzDSCons Sync on Save Daemon)Údescriptionz
--sync-nowÚ
store_truez-Run full initial sync of app/ before watching)ÚactionÚhelpzA=================================================================z-  DSCons Real-Time "Sync on Save" Hot-Watcherz  Local Source : z  Cloud Server : r‘   ú)z  Watched Dirs : z, T)Ú	recursivezI>> Hot-Watcher dang chay... Moi khi bam Ctrl+S, code se tu day len Cloud!z   (Bam Ctrl+C de dung)r@   z
>> Dung Hot-Watcher.)ÚargparseÚArgumentParserÚadd_argumentÚ
parse_argsr…   rg   r€   r~   ÚjoinrA   Úsync_nowr«   rG   r   Úschedulerc   rm   r–   ÚsleepÚKeyboardInterruptÚstop)Úparserre   ÚhandlerÚobservers       r;   ÚmainrÀ   ×   s°  € ÝÔ$Ð1MÐNÑNÔN€FØ
×ÒØ˜\Ð0_ð ñ ô ð ð ×ÒÑÔ€Då	ˆ(�O„O€OÝ	Ð
;Ñ<Ô<Ð<Ý	Ð
*�jÐ
*Ð
*Ñ+Ô+Ð+Ý	Ð
;�kÐ
;Ð
;­[Ð
;Ð
;Ð
;Ñ<Ô<Ð<Ý	Ð
5˜dŸiši­
Ñ3Ô3Ð
5Ð
5Ñ6Ô6Ð6Ý	ˆ(�O„O€Oà„}ð ÝÑÔÐå‰mŒm€GÝ‰zŒz€HØ×Ò�g�s¥:™œ¸$ÐÑ?Ô?Ð?Ø‡N‚NÑÔÐå	Ð
UÑVÔVÐVÝ	Ð
#Ñ$Ô$Ð$ðð	ÝŒJ�q‰MŒMˆMð	øåð ð ð ÝÐ&Ñ'Ô'Ð'Ø�Š‰Œˆˆˆðøøøð ‡M‚M�O„O€O€O€Os   ÅE4 Å4-F$Æ#F$Ú__main__)r-   r   r.   r/   )r.   rW   )'Ú__doc__Ú
__future__r   r³   Úpathlibr   r�   ÚsysrQ   r–   Útypingr   Úhasattrrœ   r   rš   Úwatchdog.eventsr
   r   Úwatchdog.observersr   Ú__file__Úresolver—   rg   r€   r~   Úhomer   rA   rC   r5   r8   r<   rE   rG   r«   rÀ   r¥   © r=   r;   ú<module>rÎ      s9  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ø 
€
€
€
Ø Ð Ð Ð Ø €€€Ø Ð Ð Ð Ð Ð ð €7ˆ3Œ:�}Ñ%Ô%ð ?Ø„J×Ò G°IÐÑ>Ô>Ð>Ø
€7ˆ3Œ:�}Ñ%Ô%ð ?Ø„J×Ò G°IÐÑ>Ô>Ð>à CÐ CÐ CÐ CÐ CÐ CÐ CÐ CØ 'Ð 'Ð 'Ð 'Ð 'Ð 'àˆT�(‰^Œ^×#Ò#Ñ%Ô%Ô,Ô3€
Ø€Ø€Ø
ˆ$Œ)‰+Œ+˜Ñ
Ð!8Ñ
8€àEÐEÐE€
ðð ð €
ðð ð €ð	ð 	ð 	Ð ð	ð 	ð 	ð 	ðð ð ð ð_Qð _Qð _Qð _Qð _QÐ(ñ _Qô _Qð _QðD=ð =ð =ð =ð,ð ð ð ðD ˆzÒÐØ€D�F„F€F€F€Fð Ðr=   