
    zc*.                     t    d Z ddlZddlZddlmZ  G d d          Z G d d          Z G d d	          ZdS )
u  
:module: watchdog.utils.dirsnapshot
:synopsis: Directory snapshots and comparison.
:author: yesudeep@google.com (Yesudeep Mangalapilly)
:author: contact@tiger-222.fr (Mickaël Schoentgen)

.. ADMONITION:: Where are the moved events? They "disappeared"

        This implementation does not take partition boundaries
        into consideration. It will only work when the directory
        tree is entirely on the same file system. More specifically,
        any part of the code that depends on inode numbers can
        break if partition boundaries are crossed. In these cases,
        the snapshot diff will represent file/directory movement as
        created and deleted events.

Classes
-------
.. autoclass:: DirectorySnapshot
   :members:
   :show-inheritance:

.. autoclass:: DirectorySnapshotDiff
   :members:
   :show-inheritance:

.. autoclass:: EmptyDirectorySnapshot
   :members:
   :show-inheritance:

    N)S_ISDIRc                       e Zd ZdZddZd Zd Zed             Zed             Z	ed             Z
ed	             Zed
             Zed             Zed             Zed             ZdS )DirectorySnapshotDiffa  
    Compares two directory snapshots and creates an object that represents
    the difference between the two snapshots.

    :param ref:
        The reference directory snapshot.
    :type ref:
        :class:`DirectorySnapshot`
    :param snapshot:
        The directory snapshot which will be compared
        with the reference snapshot.
    :type snapshot:
        :class:`DirectorySnapshot`
    :param ignore_device:
        A boolean indicating whether to ignore the device id or not.
        By default, a file may be uniquely identified by a combination of its first
        inode and its device id. The problem is that the device id may (or may not)
        change between system boots. This problem would cause the DirectorySnapshotDiff
        to think a file has been deleted and created again but it would be the
        exact same file.
        Set to True only if you are sure you will always use the same device.
    :type ignore_device:
        :class:`bool`
    Fc                    j         j         z
  }j         j         z
  }|rd }nd }j         j         z  D ]F} ||           ||          k    r*|                    |           |                    |           Gt                      }t          |          D ]Z}                    |          }	                    |	          }
|
r,|                    |           |                    ||
f           [t          |          D ]Z}                    |          }	                    |	          }|r,|                    |           |                    ||f           [t                      }j         j         z  D ]} ||           ||          k    rm                    |                              |          k    s,                    |                              |          k    r|                    |           |D ]r\  }}
                    |                              |
          k    s,                    |                              |
          k    r|                    |           sfd|D             | _        fd|D             | _	        fd|D             | _
        fd|D             | _        t          |t          | j                  z
            | _        t          |t          | j	                  z
            | _        t          |t          | j
                  z
            | _        t          |t          | j                  z
            | _        d S )Nc                 8    |                      |          d         S )Nr   inode	directory	full_paths     :lib/python3.11/site-packages/watchdog/utils/dirsnapshot.py	get_inodez1DirectorySnapshotDiff.__init__.<locals>.get_inodeW   s     y11!44    c                 ,    |                      |          S Nr   r
   s     r   r   z1DirectorySnapshotDiff.__init__.<locals>.get_inodeZ   s     y111r   c                 >    g | ]}                     |          |S  isdir).0pathsnapshots     r   
<listcomp>z2DirectorySnapshotDiff.__init__.<locals>.<listcomp>   s*    OOOt(..:N:NOdOOOr   c                 >    g | ]}                     |          |S r   r   r   r   refs     r   r   z2DirectorySnapshotDiff.__init__.<locals>.<listcomp>   s(    JJJt#))D//JdJJJr   c                 >    g | ]}                     |          |S r   r   r   s     r   r   z2DirectorySnapshotDiff.__init__.<locals>.<listcomp>   s(    LLLCIIdOOLtLLLr   c                 H    g | ]\  }}                     |          ||fS r   r   )r   frmtor   s      r   r   z2DirectorySnapshotDiff.__init__.<locals>.<listcomp>   s0    OOO)3		#OS"IOOOr   )pathsaddsetr	   r   removemtimesize_dirs_created_dirs_deleted_dirs_modified_dirs_movedlist_files_created_files_deleted_files_modified_files_moved)selfr   r   ignore_devicecreateddeletedr   r   movedr	   new_pathold_pathmodifieds    ``          r   __init__zDirectorySnapshotDiff.__init__R   s   .39,)hn, 	25 5 5 52 2 2 I. 	" 	"Dyd##yy4'@'@@ "D!!!D!!! LL 	, 	,DIIdOOE}}U++H ,t$$$		4*+++LL 	, 	,DNN4((ExxH ,t$$$		8T*+++ 55I. 	' 	'Dyd##yy4'@'@@ '99T??hnnT&:&:: 'chhtnnPXP]P]^bPcPc>c 'LL&&&$) 	' 	' Xxyy""hnnX&>&>> '#((8BTBTX`XeXefnXoXoBo 'X&&&OOOOwOOOJJJJwJJJLLLLLLLOOOOuOOO"7S1C-D-D#DEE"7S1C-D-D#DEE#Hs43F/G/G$GHH T-=)>)>!>??r   c                 *    |                                  S r   __repr__r0   s    r   __str__zDirectorySnapshotDiff.__str__       }}r   c                    d}|                     t          |           j        t          | j                  t          | j                  t          | j                  t          | j                  t          | j                  t          | j	                  t          | j
                  t          | j                  	  	        S )Nzz<{0} files(created={1}, deleted={2}, modified={3}, moved={4}), folders(created={5}, deleted={6}, modified={7}, moved={8})>)formattype__name__lenr,   r-   r.   r/   r'   r(   r)   r*   )r0   fmts     r   r;   zDirectorySnapshotDiff.__repr__   s    K 	 zzJJ#$$#$$$%%!"""##"###$$ !!

 

 
	
r   c                     | j         S )z List of files that were created.)r,   r<   s    r   files_createdz#DirectorySnapshotDiff.files_created        ""r   c                     | j         S )z List of files that were deleted.)r-   r<   s    r   files_deletedz#DirectorySnapshotDiff.files_deleted   rG   r   c                     | j         S )z!List of files that were modified.)r.   r<   s    r   files_modifiedz$DirectorySnapshotDiff.files_modified   s     ##r   c                     | j         S )z
        List of files that were moved.

        Each event is a two-tuple the first item of which is the path
        that has been renamed to the second item in the tuple.
        )r/   r<   s    r   files_movedz!DirectorySnapshotDiff.files_moved   s       r   c                     | j         S )z9
        List of directories that were modified.
        )r)   r<   s    r   dirs_modifiedz#DirectorySnapshotDiff.dirs_modified   s    
 ""r   c                     | j         S )z
        List of directories that were moved.

        Each event is a two-tuple the first item of which is the path
        that has been renamed to the second item in the tuple.
        )r*   r<   s    r   
dirs_movedz DirectorySnapshotDiff.dirs_moved   s     r   c                     | j         S )z8
        List of directories that were deleted.
        )r(   r<   s    r   dirs_deletedz"DirectorySnapshotDiff.dirs_deleted       
 !!r   c                     | j         S )z8
        List of directories that were created.
        )r'   r<   s    r   dirs_createdz"DirectorySnapshotDiff.dirs_created   rT   r   N)F)rB   
__module____qualname____doc__r8   r=   r;   propertyrF   rI   rK   rM   rO   rQ   rS   rV   r   r   r   r   r   8   s-        26@ 6@ 6@ 6@p  
 
 
" # # X# # # X# $ $ X$ ! ! X! # # X#     X  " " X" " " X" " "r   r   c                       e Zd ZdZdej        ej        fdZd Ze	d             Z
d Zd Zd Zd	 Zd
 Zd Zd Zd Zd ZdS )DirectorySnapshota  
    A snapshot of stat information of files in a directory.

    :param path:
        The directory path for which a snapshot should be taken.
    :type path:
        ``str``
    :param recursive:
        ``True`` if the entire directory tree should be included in the
        snapshot; ``False`` otherwise.
    :type recursive:
        ``bool``
    :param stat:
        Use custom stat function that returns a stat structure for path.
        Currently only st_dev, st_ino, st_mode and st_mtime are needed.

        A function taking a ``path`` as argument which will be called
        for every entry in the directory tree.
    :param listdir:
        Use custom listdir function. For details see ``os.scandir``.
    Tc                 0   || _         || _        || _        i | _        i | _        |                     |          }|| j        |<   || j        |j        |j        f<   |                     |          D ]'\  }}|j        |j        f}|| j        |<   || j        |<   (d S r   )	recursivestatlistdir
_stat_info_inode_to_pathst_inost_devwalk)r0   r   r^   r_   r`   stpis           r   r8   zDirectorySnapshot.__init__   s    "	 YYt__ "6:RY	23YYt__ 	$ 	$EArBI&A%&D"!#DOA	$ 	$r   c              #     K   	 fd|                                D             }nC# t          $ r6}|j        t          j        t          j        t          j        fv rY d }~d S  d }~ww xY wg }|D ]C}	 ||                     |          f}|                    |           |V  4# t          $ r Y @w xY w| j        rI|D ]H\  }}	 t          |j
                  r|                     |          D ]}|V  7# t          $ r Y Cw xY wd S d S )Nc           	          g | ]>}t           j                            t          |t                    r|n|j                  ?S r   )osr   join
isinstancestrname)r   entryroots     r   r   z*DirectorySnapshot.walk.<locals>.<listcomp>  sN     6 6 6 W\\$E31G1G(WUZXX 6 6 6r   )r`   OSErrorerrnoENOENTENOTDIREINVALr_   appendr^   r   st_modere   PermissionError)	r0   rq   r!   eentriesrg   rp   r   rf   s	    `       r   re   zDirectorySnapshot.walk   s     	6 6 6 6"&,,t"4"46 6 6EE 	 	 	
 w5<EE 	  	 	ADIIaLL)u%%%    > 	#  brz** (%)YYt__ ( (E"'KKKK&   D	 	 s>   !' 
A'*A"!A""A'10B""
B/.B/0C22
C?>C?c                 N    t          | j                                                  S )z>
        Set of file/directory paths in the snapshot.
        )r#   ra   keysr<   s    r   r!   zDirectorySnapshot.paths   s     
 4?''))***r   c                 6    | j                             |          S )zN
        Returns path for id. None if id is unknown to this snapshot.
        )rb   get)r0   ids     r   r   zDirectorySnapshot.path'  s     "&&r***r   c                 8    | j         |         }|j        |j        fS )z Returns an id for path. )ra   rc   rd   )r0   r   rf   s      r   r	   zDirectorySnapshot.inode-  s    _T"	29%%r   c                 @    t          | j        |         j                  S r   )r   ra   rx   r0   r   s     r   r   zDirectorySnapshot.isdir2  s    tt,4555r   c                 &    | j         |         j        S r   )ra   st_mtimer   s     r   r%   zDirectorySnapshot.mtime5  s    t$--r   c                 &    | j         |         j        S r   )ra   st_sizer   s     r   r&   zDirectorySnapshot.size8  s    t$,,r   c                     | j         |         S )a  
        Returns a stat information object for the specified path from
        the snapshot.

        Attached information is subject to change. Do not use unless
        you specify `stat` in constructor. Use :func:`inode`, :func:`mtime`,
        :func:`isdir` instead.

        :param path:
            The path for which stat information should be obtained
            from a snapshot.
        )ra   r   s     r   	stat_infozDirectorySnapshot.stat_info;  s     t$$r   c                 "    t          ||           S )zAllow subtracting a DirectorySnapshot object instance from
        another.

        :returns:
            A :class:`DirectorySnapshotDiff` object.
        )r   )r0   previous_dirsnaps     r   __sub__zDirectorySnapshot.__sub__J  s     %%5t<<<r   c                 *    |                                  S r   r:   r<   s    r   r=   zDirectorySnapshot.__str__S  r>   r   c                 *    t          | j                  S r   )rn   ra   r<   s    r   r;   zDirectorySnapshot.__repr__V  s    4?###r   N)rB   rW   rX   rY   rk   r_   scandirr8   re   rZ   r!   r   r	   r   r%   r&   r   r   r=   r;   r   r   r   r\   r\      s         , (,grz$ $ $ $$  @ + + X++ + +& & &
6 6 6. . .- - -% % %= = =  $ $ $ $ $r   r\   c                   >    e Zd ZdZed             Zed             ZdS )EmptyDirectorySnapshotzClass to implement an empty snapshot. This is used together with
    DirectorySnapshot and DirectorySnapshotDiff in order to get all the files/folders
    in the directory as created.
    c                     dS )zMock up method to return the path of the received inode. As the snapshot
        is intended to be empty, it always returns None.

        :returns:
            None.
        Nr   )_s    r   r   zEmptyDirectorySnapshot.path`  s	     tr   c                     t                      S )zMock up method to return a set of file/directory paths in the snapshot. As
        the snapshot is intended to be empty, it always returns an empty set.

        :returns:
            An empty set.
        )r#   r<   s    r   r!   zEmptyDirectorySnapshot.pathsj  s     uur   N)rB   rW   rX   rY   staticmethodr   rZ   r!   r   r   r   r   r   Z  sT         
   \   X  r   r   )rY   rs   rk   r_   r   r   r\   r   r   r   r   <module>r      s   & @  				      \" \" \" \" \" \" \" \"~@$ @$ @$ @$ @$ @$ @$ @$F         r   