U
    ”Ê¹j<†  ã                   @   s�  d 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lm	Z	 ddl
mZmZmZmZmZmZmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZ e e¡Zed ZdgZedd�G dd„ dƒƒZ edd�G dd„ dƒƒZ!edd�G dd„ dƒƒZ"edd�G dd„ dƒƒZ#edd�G dd„ dƒƒZ$d+eee%e	f  e$dœdd„Z&e	e"dœdd „Z'e(e%d!œd"d#„Z)d$Z*e+e%d%œd&d'„Z,e	e%dd(œd)d*„Z-dS ),z4Contains utilities to manage the HF cache directory.é    N)Údefaultdict)Ú	dataclass)ÚPath)ÚDictÚ	FrozenSetÚListÚLiteralÚOptionalÚSetÚUnion)ÚCacheNotFoundÚCorruptedCacheExceptioné   )Útabulate)ÚHF_HUB_CACHEé   )Úlogging)ÚmodelÚdatasetÚspacez	.DS_StoreT)Úfrozenc                   @   sx   e Zd ZU dZeed< eed< eed< eed< eed< eed< e	edœd	d
„ƒZ
e	edœdd„ƒZe	edœdd„ƒZdS )ÚCachedFileInfoaò  Frozen data structure holding information about a single cached file.

    Args:
        file_name (`str`):
            Name of the file. Example: `config.json`.
        file_path (`Path`):
            Path of the file in the `snapshots` directory. The file path is a symlink
            referring to a blob in the `blobs` folder.
        blob_path (`Path`):
            Path of the blob file. This is equivalent to `file_path.resolve()`.
        size_on_disk (`int`):
            Size of the blob file in bytes.
        blob_last_accessed (`float`):
            Timestamp of the last time the blob file has been accessed (from any
            revision).
        blob_last_modified (`float`):
            Timestamp of the last time the blob file has been modified/created.

    > [!WARNING]
    > `blob_last_accessed` and `blob_last_modified` reliability can depend on the OS you
    > are using. See [python documentation](https://docs.python.org/3/library/os.html#os.stat_result)
    > for more details.
    Ú	file_nameÚ	file_pathÚ	blob_pathÚsize_on_diskÚblob_last_accessedÚblob_last_modified©Úreturnc                 C   s
   t | jƒS )zº
        (property) Timestamp of the last time the blob file has been accessed (from any
        revision), returned as a human-readable string.

        Example: "2 weeks ago".
        )Ú_format_timesincer   ©Úself© r#   úc/var/www/html/bwave/python/venv/lib/python3.8/site-packages/huggingface_hub/utils/_cache_manager.pyÚblob_last_accessed_strJ   s    z%CachedFileInfo.blob_last_accessed_strc                 C   s
   t | jƒS )z¦
        (property) Timestamp of the last time the blob file has been modified, returned
        as a human-readable string.

        Example: "2 weeks ago".
        )r    r   r!   r#   r#   r$   Úblob_last_modified_strT   s    z%CachedFileInfo.blob_last_modified_strc                 C   s
   t | jƒS )zi
        (property) Size of the blob file as a human-readable string.

        Example: "42.2K".
        ©Ú_format_sizer   r!   r#   r#   r$   Úsize_on_disk_str^   s    zCachedFileInfo.size_on_disk_strN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__r   ÚintÚfloatÚpropertyr%   r&   r)   r#   r#   r#   r$   r   (   s   
		r   c                   @   s€   e Zd ZU dZeed< eed< eed< ee	 ed< ee ed< e
ed< eedœd	d
„ƒZeedœdd„ƒZeedœdd„ƒZdS )ÚCachedRevisionInfoa.  Frozen data structure holding information about a revision.

    A revision correspond to a folder in the `snapshots` folder and is populated with
    the exact tree structure as the repo on the Hub but contains only symlinks. A
    revision can be either referenced by 1 or more `refs` or be "detached" (no refs).

    Args:
        commit_hash (`str`):
            Hash of the revision (unique).
            Example: `"9338f7b671827df886678df2bdd7cc7b4f36dffd"`.
        snapshot_path (`Path`):
            Path to the revision directory in the `snapshots` folder. It contains the
            exact tree structure as the repo on the Hub.
        files: (`FrozenSet[CachedFileInfo]`):
            Set of [`~CachedFileInfo`] describing all files contained in the snapshot.
        refs (`FrozenSet[str]`):
            Set of `refs` pointing to this revision. If the revision has no `refs`, it
            is considered detached.
            Example: `{"main", "2.4.0"}` or `{"refs/pr/1"}`.
        size_on_disk (`int`):
            Sum of the blob file sizes that are symlink-ed by the revision.
        last_modified (`float`):
            Timestamp of the last time the revision has been created/modified.

    > [!WARNING]
    > `last_accessed` cannot be determined correctly on a single revision as blob files
    > are shared across revisions.

    > [!WARNING]
    > `size_on_disk` is not necessarily the sum of all file sizes because of possible
    > duplicated files. Besides, only blobs are taken into account, not the (negligible)
    > size of folders and symlinks.
    Úcommit_hashÚsnapshot_pathr   ÚfilesÚrefsÚlast_modifiedr   c                 C   s
   t | jƒS )z¥
        (property) Timestamp of the last time the revision has been modified, returned
        as a human-readable string.

        Example: "2 weeks ago".
        ©r    r8   r!   r#   r#   r$   Úlast_modified_str”   s    z$CachedRevisionInfo.last_modified_strc                 C   s
   t | jƒS ©zn
        (property) Sum of the blob file sizes as a human-readable string.

        Example: "42.2K".
        r'   r!   r#   r#   r$   r)   ž   s    z#CachedRevisionInfo.size_on_disk_strc                 C   s
   t | jƒS )zC
        (property) Total number of files in the revision.
        )Úlenr6   r!   r#   r#   r$   Únb_files§   s    zCachedRevisionInfo.nb_filesN)r*   r+   r,   r-   r.   r/   r   r0   r   r   r1   r2   r:   r)   r=   r#   r#   r#   r$   r3   h   s   
"	r3   c                   @   s¦   e Zd ZU dZeed< eed< eed< eed< eed< e	e
 ed< eed< eed	< eed
œdd„ƒZeed
œdd„ƒZeed
œdd„ƒZeeee
f d
œdd„ƒZdS )ÚCachedRepoInfoaF  Frozen data structure holding information about a cached repository.

    Args:
        repo_id (`str`):
            Repo id of the repo on the Hub. Example: `"google/fleurs"`.
        repo_type (`Literal["dataset", "model", "space"]`):
            Type of the cached repo.
        repo_path (`Path`):
            Local path to the cached repo.
        size_on_disk (`int`):
            Sum of the blob file sizes in the cached repo.
        nb_files (`int`):
            Total number of blob files in the cached repo.
        revisions (`FrozenSet[CachedRevisionInfo]`):
            Set of [`~CachedRevisionInfo`] describing all revisions cached in the repo.
        last_accessed (`float`):
            Timestamp of the last time a blob file of the repo has been accessed.
        last_modified (`float`):
            Timestamp of the last time a blob file of the repo has been modified/created.

    > [!WARNING]
    > `size_on_disk` is not necessarily the sum of all revisions sizes because of
    > duplicated files. Besides, only blobs are taken into account, not the (negligible)
    > size of folders and symlinks.

    > [!WARNING]
    > `last_accessed` and `last_modified` reliability can depend on the OS you are using.
    > See [python documentation](https://docs.python.org/3/library/os.html#os.stat_result)
    > for more details.
    Úrepo_idÚ	repo_typeÚ	repo_pathr   r=   Ú	revisionsÚlast_accessedr8   r   c                 C   s
   t | jƒS )zŸ
        (property) Last time a blob file of the repo has been accessed, returned as a
        human-readable string.

        Example: "2 weeks ago".
        )r    rC   r!   r#   r#   r$   Úlast_accessed_strÚ   s    z CachedRepoInfo.last_accessed_strc                 C   s
   t | jƒS )zŸ
        (property) Last time a blob file of the repo has been modified, returned as a
        human-readable string.

        Example: "2 weeks ago".
        r9   r!   r#   r#   r$   r:   ä   s    z CachedRepoInfo.last_modified_strc                 C   s
   t | jƒS r;   r'   r!   r#   r#   r$   r)   î   s    zCachedRepoInfo.size_on_disk_strc                 C   s   dd„ | j D ƒS )zQ
        (property) Mapping between `refs` and revision data structures.
        c                 S   s   i | ]}|j D ]
}||“qqS r#   )r7   )Ú.0ÚrevisionÚrefr#   r#   r$   Ú
<dictcomp>ü   s
        z'CachedRepoInfo.refs.<locals>.<dictcomp>)rB   r!   r#   r#   r$   r7   ÷   s    zCachedRepoInfo.refsN)r*   r+   r,   r-   r.   r/   ÚREPO_TYPE_Tr   r0   r   r3   r1   r2   rD   r:   r)   r   r7   r#   r#   r#   r$   r>   ¯   s"   
		r>   c                   @   sj   e Zd ZU dZeed< ee ed< ee ed< ee ed< ee ed< ee	dœdd	„ƒZ
d
dœdd„Zd
S )ÚDeleteCacheStrategyaÒ  Frozen data structure holding the strategy to delete cached revisions.

    This object is not meant to be instantiated programmatically but to be returned by
    [`~utils.HFCacheInfo.delete_revisions`]. See documentation for usage example.

    Args:
        expected_freed_size (`float`):
            Expected freed size once strategy is executed.
        blobs (`FrozenSet[Path]`):
            Set of blob file paths to be deleted.
        refs (`FrozenSet[Path]`):
            Set of reference file paths to be deleted.
        repos (`FrozenSet[Path]`):
            Set of entire repo paths to be deleted.
        snapshots (`FrozenSet[Path]`):
            Set of snapshots to be deleted (directory of symlinks).
    Úexpected_freed_sizeÚblobsr7   ÚreposÚ	snapshotsr   c                 C   s
   t | jƒS )zt
        (property) Expected size that will be freed as a human-readable string.

        Example: "42.2K".
        )r(   rK   r!   r#   r#   r$   Úexpected_freed_size_str  s    z+DeleteCacheStrategy.expected_freed_size_strNc                 C   sx   | j D ]}t|dd� q| jD ]}t|dd� q| jD ]}t|dd� q6| jD ]}t|dd� qNt d| j› d�¡ dS )	aŠ  Execute the defined strategy.

        > [!WARNING]
        > If this method is interrupted, the cache might get corrupted. Deletion order is
        > implemented so that references and symlinks are deleted before the actual blob
        > files.

        > [!WARNING]
        > This method is irreversible. If executed, cached files are erased and must be
        > downloaded again.
        Úrepo)Ú	path_typeZsnapshotrG   ZblobzCache deletion done. Saved Ú.N)rM   Ú_try_delete_pathrN   r7   rL   ÚloggerÚinforO   )r"   Úpathr#   r#   r$   Úexecute"  s    



zDeleteCacheStrategy.execute)r*   r+   r,   r-   r0   r/   r   r   r2   r.   rO   rW   r#   r#   r#   r$   rJ   ÿ   s   
rJ   c                   @   sj   e Zd ZU dZeed< ee ed< ee	 ed< e
edœdd„ƒZeedœd	d
„Zddœeedœdd„ZdS )ÚHFCacheInfoas  Frozen data structure holding information about the entire cache-system.

    This data structure is returned by [`scan_cache_dir`] and is immutable.

    Args:
        size_on_disk (`int`):
            Sum of all valid repo sizes in the cache-system.
        repos (`FrozenSet[CachedRepoInfo]`):
            Set of [`~CachedRepoInfo`] describing all valid cached repos found on the
            cache-system while scanning.
        warnings (`List[CorruptedCacheException]`):
            List of [`~CorruptedCacheException`] that occurred while scanning the cache.
            Those exceptions are captured so that the scan can continue. Corrupted repos
            are skipped from the scan.

    > [!WARNING]
    > Here `size_on_disk` is equal to the sum of all repo sizes (only blobs). However if
    > some cached repos are corrupted, their sizes are not taken into account.
    r   rM   Úwarningsr   c                 C   s
   t | jƒS )z‹
        (property) Sum of all valid repo sizes in the cache-system as a human-readable
        string.

        Example: "42.2K".
        r'   r!   r#   r#   r$   r)   _  s    zHFCacheInfo.size_on_disk_str)rB   r   c                 G   sš  t |ƒ}tt ƒ}| jD ]4}|jD ](}|j|kr ||  |¡ | |j¡ q qt|ƒdkrnt 	dd 
|¡› �¡ t ƒ }t ƒ }t ƒ }t ƒ }	d}
| ¡ D ]ä\}}|j| }t|ƒdkrÈ| |j¡ |
|j7 }
q’|D ]¨}|	 |j¡ |jD ]}| |jd | ¡ qâ|jD ]p}|j|k�rd}|D ]8}|jD ]}|j|jk�r$d} �qD�q$|�s �qT�q|�r| |j¡ |
|j7 }
�qqÌq’tt|ƒt|ƒt|ƒt|	ƒ|
d�S )a’  Prepare the strategy to delete one or more revisions cached locally.

        Input revisions can be any revision hash. If a revision hash is not found in the
        local cache, a warning is thrown but no error is raised. Revisions can be from
        different cached repos since hashes are unique across repos,

        Examples:
        ```py
        >>> from huggingface_hub import scan_cache_dir
        >>> cache_info = scan_cache_dir()
        >>> delete_strategy = cache_info.delete_revisions(
        ...     "81fd1d6e7847c99f5862c9fb81387956d99ec7aa"
        ... )
        >>> print(f"Will free {delete_strategy.expected_freed_size_str}.")
        Will free 7.9K.
        >>> delete_strategy.execute()
        Cache deletion done. Saved 7.9K.
        ```

        ```py
        >>> from huggingface_hub import scan_cache_dir
        >>> scan_cache_dir().delete_revisions(
        ...     "81fd1d6e7847c99f5862c9fb81387956d99ec7aa",
        ...     "e2983b237dccf3ab4937c97fa717319a9ca1a96d",
        ...     "6c0e6080953db56375760c0471a8c5f2929baf11",
        ... ).execute()
        Cache deletion done. Saved 8.6G.
        ```

        > [!WARNING]
        > `delete_revisions` returns a [`~utils.DeleteCacheStrategy`] object that needs to
        > be executed. The [`~utils.DeleteCacheStrategy`] is not meant to be modified but
        > allows having a dry run before actually executing the deletion.
        r   z,Revision(s) not found - cannot delete them: ú, r7   TF)rL   r7   rM   rN   rK   )Úsetr   rM   rB   r4   ÚaddÚremover<   rT   ÚwarningÚjoinÚitemsrA   r   r5   r7   r6   r   rJ   Ú	frozenset)r"   rB   Zhashes_to_deleteZrepos_with_revisionsrP   rF   Zdelete_strategy_blobsZdelete_strategy_refsZdelete_strategy_reposZdelete_strategy_snapshotsZ#delete_strategy_expected_freed_sizeZaffected_repoZrevisions_to_deleteZother_revisionsZrevision_to_deleterG   ÚfileZis_file_aloneZrev_filer#   r#   r$   Údelete_revisionsi  sX    #









ûzHFCacheInfo.delete_revisionsr   )Ú	verbosity)rd   r   c             
   C   st   |dkr<t dd„ t| jdd„ d�D ƒddd	d
ddddgd�S t dd„ t| jdd„ d�D ƒdddd	d
dddgd�S dS )a}  Generate a table from the [`HFCacheInfo`] object.

        Pass `verbosity=0` to get a table with a single row per repo, with columns
        "repo_id", "repo_type", "size_on_disk", "nb_files", "last_accessed", "last_modified", "refs", "local_path".

        Pass `verbosity=1` to get a table with a row per repo and revision (thus multiple rows can appear for a single repo), with columns
        "repo_id", "repo_type", "revision", "size_on_disk", "nb_files", "last_modified", "refs", "local_path".

        Example:
        ```py
        >>> from huggingface_hub.utils import scan_cache_dir

        >>> hf_cache_info = scan_cache_dir()
        HFCacheInfo(...)

        >>> print(hf_cache_info.export_as_table())
        REPO ID                                             REPO TYPE SIZE ON DISK NB FILES LAST_ACCESSED LAST_MODIFIED REFS LOCAL PATH
        --------------------------------------------------- --------- ------------ -------- ------------- ------------- ---- --------------------------------------------------------------------------------------------------
        roberta-base                                        model             2.7M        5 1 day ago     1 week ago    main ~/.cache/huggingface/hub/models--roberta-base
        suno/bark                                           model             8.8K        1 1 week ago    1 week ago    main ~/.cache/huggingface/hub/models--suno--bark
        t5-base                                             model           893.8M        4 4 days ago    7 months ago  main ~/.cache/huggingface/hub/models--t5-base
        t5-large                                            model             3.0G        4 5 weeks ago   5 months ago  main ~/.cache/huggingface/hub/models--t5-large

        >>> print(hf_cache_info.export_as_table(verbosity=1))
        REPO ID                                             REPO TYPE REVISION                                 SIZE ON DISK NB FILES LAST_MODIFIED REFS LOCAL PATH
        --------------------------------------------------- --------- ---------------------------------------- ------------ -------- ------------- ---- -----------------------------------------------------------------------------------------------------------------------------------------------------
        roberta-base                                        model     e2da8e2f811d1448a5b465c236feacd80ffbac7b         2.7M        5 1 week ago    main ~/.cache/huggingface/hub/models--roberta-base/snapshots/e2da8e2f811d1448a5b465c236feacd80ffbac7b
        suno/bark                                           model     70a8a7d34168586dc5d028fa9666aceade177992         8.8K        1 1 week ago    main ~/.cache/huggingface/hub/models--suno--bark/snapshots/70a8a7d34168586dc5d028fa9666aceade177992
        t5-base                                             model     a9723ea7f1b39c1eae772870f3b547bf6ef7e6c1       893.8M        4 7 months ago  main ~/.cache/huggingface/hub/models--t5-base/snapshots/a9723ea7f1b39c1eae772870f3b547bf6ef7e6c1
        t5-large                                            model     150ebc2c4b72291e770f58e6057481c8d2ed331a         3.0G        4 5 months ago  main ~/.cache/huggingface/hub/models--t5-large/snapshots/150ebc2c4b72291e770f58e6057481c8d2ed331a
        ```

        Args:
            verbosity (`int`, *optional*):
                The verbosity level. Defaults to 0.

        Returns:
            `str`: The table as a string.
        r   c                 S   sD   g | ]<}|j |jd  |j¡|j|j|jd t|j	ƒ¡t
|jƒg‘qS )ú{:>12}rZ   )r?   r@   Úformatr)   r=   rD   r:   r_   Úsortedr7   r.   rA   ©rE   rP   r#   r#   r$   Ú
<listcomp>÷  s   ÷
øz/HFCacheInfo.export_as_table.<locals>.<listcomp>c                 S   s   | j S ©N©rA   ©rP   r#   r#   r$   Ú<lambda>  ó    z-HFCacheInfo.export_as_table.<locals>.<lambda>©ÚkeyzREPO IDz	REPO TYPEzSIZE ON DISKzNB FILESZLAST_ACCESSEDZLAST_MODIFIEDZREFSz
LOCAL PATH)ÚrowsÚheadersc                 S   s\   g | ]T}t |jd d„ d�D ]<}|j|j|jd |j¡|j|jd 	t |j
ƒ¡t|jƒg‘qqS )c                 S   s   | j S rj   )r4   )rF   r#   r#   r$   rm     rn   z8HFCacheInfo.export_as_table.<locals>.<listcomp>.<lambda>ro   re   rZ   )rg   rB   r?   r@   r4   rf   r)   r=   r:   r_   r7   r.   r5   )rE   rP   rF   r#   r#   r$   ri     s    ö
øc                 S   s   | j S rj   rk   rl   r#   r#   r$   rm     rn   ZREVISIONN)r   rg   rM   )r"   rd   r#   r#   r$   Úexport_as_tableÍ  s:    (õøòõøñzHFCacheInfo.export_as_tableN)r*   r+   r,   r-   r0   r/   r   r>   r   r   r2   r.   r)   rJ   rc   rs   r#   r#   r#   r$   rX   E  s   
	drX   )Ú	cache_dirr   c                 C   sÔ   | dkrt } t| ƒ ¡  ¡ } |  ¡ s8td| › d�| d�‚|  ¡ rPtd| › d�ƒ‚tƒ }g }|  	¡ D ]P}|j
dkrrqbz| t|ƒ¡ W qb tk
r° } z| |¡ W 5 d}~X Y qbX qbtt|ƒtdd„ |D ƒƒ|d	�S )
af  Scan the entire HF cache-system and return a [`~HFCacheInfo`] structure.

    Use `scan_cache_dir` in order to programmatically scan your cache-system. The cache
    will be scanned repo by repo. If a repo is corrupted, a [`~CorruptedCacheException`]
    will be thrown internally but captured and returned in the [`~HFCacheInfo`]
    structure. Only valid repos get a proper report.

    ```py
    >>> from huggingface_hub import scan_cache_dir

    >>> hf_cache_info = scan_cache_dir()
    HFCacheInfo(
        size_on_disk=3398085269,
        repos=frozenset({
            CachedRepoInfo(
                repo_id='t5-small',
                repo_type='model',
                repo_path=PosixPath(...),
                size_on_disk=970726914,
                nb_files=11,
                revisions=frozenset({
                    CachedRevisionInfo(
                        commit_hash='d78aea13fa7ecd06c29e3e46195d6341255065d5',
                        size_on_disk=970726339,
                        snapshot_path=PosixPath(...),
                        files=frozenset({
                            CachedFileInfo(
                                file_name='config.json',
                                size_on_disk=1197
                                file_path=PosixPath(...),
                                blob_path=PosixPath(...),
                            ),
                            CachedFileInfo(...),
                            ...
                        }),
                    ),
                    CachedRevisionInfo(...),
                    ...
                }),
            ),
            CachedRepoInfo(...),
            ...
        }),
        warnings=[
            CorruptedCacheException("Snapshots dir doesn't exist in cached repo: ..."),
            CorruptedCacheException(...),
            ...
        ],
    )
    ```

    You can also print a detailed report directly from the `hf` command line using:
    ```text
    > hf cache scan
    REPO ID                     REPO TYPE SIZE ON DISK NB FILES REFS                LOCAL PATH
    --------------------------- --------- ------------ -------- ------------------- -------------------------------------------------------------------------
    glue                        dataset         116.3K       15 1.17.0, main, 2.4.0 /Users/lucain/.cache/huggingface/hub/datasets--glue
    google/fleurs               dataset          64.9M        6 main, refs/pr/1     /Users/lucain/.cache/huggingface/hub/datasets--google--fleurs
    Jean-Baptiste/camembert-ner model           441.0M        7 main                /Users/lucain/.cache/huggingface/hub/models--Jean-Baptiste--camembert-ner
    bert-base-cased             model             1.9G       13 main                /Users/lucain/.cache/huggingface/hub/models--bert-base-cased
    t5-base                     model            10.1K        3 main                /Users/lucain/.cache/huggingface/hub/models--t5-base
    t5-small                    model           970.7M       11 refs/pr/1, main     /Users/lucain/.cache/huggingface/hub/models--t5-small

    Done in 0.0s. Scanned 6 repo(s) for a total of 3.4G.
    Got 1 warning(s) while scanning. Use -vvv to print details.
    ```

    Args:
        cache_dir (`str` or `Path`, `optional`):
            Cache directory to cache. Defaults to the default HF cache directory.

    > [!WARNING]
    > Raises:
    >
    >     `CacheNotFound`
    >       If the cache directory does not exist.
    >
    >     [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
    >       If the cache directory is a file, instead of a directory.

    Returns: a [`~HFCacheInfo`] object.
    NzCache directory not found: zM. Please use `cache_dir` argument or set `HF_HUB_CACHE` environment variable.)rt   z1Scan cache expects a directory but found a file: z.locksc                 s   s   | ]}|j V  qd S rj   )r   rh   r#   r#   r$   Ú	<genexpr>š  s     z!scan_cache_dir.<locals>.<genexpr>)rM   r   rY   )r   r   Ú
expanduserÚresolveÚexistsr   Úis_fileÚ
ValueErrorr[   ÚiterdirÚnamer\   Ú_scan_cached_repor   ÚappendrX   ra   Úsum)rt   rM   rY   rA   Úer#   r#   r$   Úscan_cache_dir,  s4    S
þ
ÿ
ýr�   )rA   r   c                    s&  |   ¡ std| › �ƒ‚d| jkr.td| › �ƒ‚| jjddd�\}}|dd… }| dd¡}|d	krxtd
|› d| › d�ƒ‚i ‰ | d }| d }| ¡ rœ|  ¡ sªtd|› �ƒ‚ttƒ}| ¡ �r.| ¡ rÒtd|› �ƒ‚| 	d¡D ]P}|  ¡ sÜ|jt
krôqÜt| |¡ƒ}| ¡ �}| ¡ }	W 5 Q R X ||	  |¡ qÜtƒ }
| ¡ D �]<}|jt
k�rR�q<| ¡ �rjtd|› �ƒ‚tƒ }| 	d¡D ]|}|  ¡ �rŒ�qzt|ƒ ¡ }| ¡ �s°td|› �ƒ‚|ˆ k�rÆ| ¡ ˆ |< | t|j|ˆ | j|ˆ | jˆ | jd�¡ �qzt|ƒdk�rt‡ fdd„|D ƒƒ}n
| ¡ j}|
 t|jt|ƒt| |jtƒ ¡ƒt‡ fdd„tdd„ |D ƒƒD ƒƒ||d�¡ �q<t|ƒdk�r¤tdt|ƒ› d| › d�ƒ‚tˆ ƒdk�ràtdd„ ˆ  ¡ D ƒƒ}tdd„ ˆ  ¡ D ƒƒ}n|  ¡ }|j}|j}t tˆ ƒ|| |t|
ƒtdd„ ˆ  ¡ D ƒƒ||d �S )!z†Scan a single cache repo and return information about it.

    Any unexpected behavior will raise a [`~CorruptedCacheException`].
    zRepo path is not a directory: z--z6Repo path is not a valid HuggingFace cache directory: r   )ÚmaxsplitNéÿÿÿÿú/>   r   r   r   z8Repo type must be `dataset`, `model` or `space`, found `z` (z).rN   r7   z,Snapshots dir doesn't exist in cached repo: z!Refs directory cannot be a file: z**/*z*Snapshots folder corrupted. Found a file: zBlob missing (broken symlink): )r   r   r   r   r   r   r   c                 3   s   | ]}ˆ |j  jV  qd S rj   )r   Úst_mtime©rE   rb   ©Z
blob_statsr#   r$   ru   ø  s     z$_scan_cached_repo.<locals>.<genexpr>c                 3   s   | ]}ˆ | j V  qd S rj   ©Úst_size)rE   r   r‡   r#   r$   ru     s    c                 s   s   | ]}|j V  qd S rj   )r   r†   r#   r#   r$   ru     s     )r4   r6   r7   r   r5   r8   z-Reference(s) refer to missing commit hashes: z (c                 s   s   | ]}|j V  qd S rj   )Úst_atime©rE   Ústatr#   r#   r$   ru     s     c                 s   s   | ]}|j V  qd S rj   )r…   r‹   r#   r#   r$   ru     s     c                 s   s   | ]}|j V  qd S rj   rˆ   r‹   r#   r#   r$   ru      s     )r=   r?   rA   r@   rB   r   rC   r8   )!Úis_dirr   r|   ÚsplitÚreplacerx   r   r[   ry   ÚglobÚFILES_TO_IGNOREr.   Úrelative_toÚopenÚreadr\   r{   r   rw   rŒ   r   r‰   rŠ   r…   r<   Úmaxr3   ra   Úpopr   ÚdictÚvaluesr>   )rA   r@   r?   Zsnapshots_pathZ	refs_pathZrefs_by_hashZref_pathÚref_nameÚfr4   Zcached_revisionsZrevision_pathÚcached_filesr   r   Zrevision_last_modifiedZrepo_last_accessedZrepo_last_modifiedZ
repo_statsr#   r‡   r$   r}   Ÿ  s®    
ÿ





úÿ
ÿøÿÿør}   )Únumr   c                 C   sD   t | ƒ}dD ]*}t|ƒdk r.|d›|› �  S |d }q|d›d�S )zkFormat size in bytes into a human-readable string.

    Taken from https://stackoverflow.com/a/1094933
    )Ú ÚKÚMÚGÚTÚPÚEÚZg     @�@z3.1fz.1fÚY)r1   Úabs)rœ   Znum_fÚunitr#   r#   r$   r(   &  s    
r(   ))Úsecondr   é<   )Úminuter©   r©   )Úhouri  é   )Údayi€Q é   )Úweeki€:	 r®   )Úmonthi �' é   )Úyeari€3áN)Útsr   c                 C   sh   t   ¡ |  }|dk rdS tD ]*\}}}t|| ƒ}|dk	r||kr qHq|› d|› |dkr^dnd› d�S )	zˆFormat timestamp in seconds into a human-readable string, relative to now.

    Vaguely inspired by Django's `timesince` formatter.
    é   za few seconds agoNú r   Úsr�   z ago)ÚtimeÚ_TIMESINCE_CHUNKSÚround)r³   ÚdeltaÚlabelÚdividerZ	max_valueÚvaluer#   r#   r$   r    ?  s    r    )rV   rQ   r   c              	   C   sœ   t  d|› d| › �¡ z"|  ¡ r,t | ¡ n
t | ¡ W n^ tk
rh   t jd|› d| › d�dd� Y n0 t	k
r–   t jd|› d| › d�dd� Y nX d	S )
aE  Try to delete a local file or folder.

    If the path does not exists, error is logged as a warning and then ignored.

    Args:
        path (`Path`)
            Path to delete. Can be a file or a folder.
        path_type (`str`)
            What path are we deleting ? Only for logging purposes. Example: "snapshot".
    zDelete z: zCouldn't delete z: file not found (ú)T)Úexc_infoz: permission denied (N)
rT   rU   ry   Úosr]   ÚshutilÚrmtreeÚFileNotFoundErrorr^   ÚPermissionError)rV   rQ   r#   r#   r$   rS   N  s     rS   )N).r-   rÀ   rÁ   r·   Úcollectionsr   Údataclassesr   Úpathlibr   Útypingr   r   r   r   r	   r
   r   Zhuggingface_hub.errorsr   r   Zcommands._cli_utilsr   Ú	constantsr   r�   r   Z
get_loggerr*   rT   rI   r‘   r   r3   r>   rJ   rX   r.   r�   r}   r0   r(   r¸   r1   r    rS   r#   r#   r#   r$   Ú<module>   s@   $
?FOE gs 