o
    hD                     @   s$  d 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
mZmZmZmZmZmZ ddlmZmZmZmZ d	d
lmZ d	dlmZ zddlmZ ddlmZ ddlmZ dZ W n e!ye   dZ Y nw ed Z"dedefddZ#dZ$G dd deZ%d8dedee" fddZ&e#	d8dedee' dee" dee' fdd Z(e#d9d!e'd"e)de)fd#d$Z*	d8d%ee dee' dee" defd&d'Z+	d8dedee' dee" dee' fd(d)Z,d9d!e'd"e)de)fd*d+Z-ded,ee' de'fd-d.Z.d/e'dee' fd0d1Z/d2e$ d3e$ d40 Z1d5ede
fd6d7Z2dS ):as  Contains command to delete some revisions from the HF cache directory.

Usage:
    huggingface-cli delete-cache
    huggingface-cli delete-cache --disable-tui
    huggingface-cli delete-cache --dir ~/.cache/huggingface/hub
    huggingface-cli delete-cache --sort=size

NOTE:
    This command is based on `InquirerPy` to build the multiselect menu in the terminal.
    This dependency has to be installed with `pip install huggingface_hub[cli]`. Since
    we want to avoid as much as possible cross-platform issues, I chose a library that
    is built on top of `python-prompt-toolkit` which seems to be a reference in terminal
    GUI (actively maintained on both Unix and Windows, 7.9k stars).

    For the moment, the TUI feature is in beta.

    See:
    - https://github.com/kazhala/InquirerPy
    - https://inquirerpy.readthedocs.io/en/latest/
    - https://github.com/prompt-toolkit/python-prompt-toolkit

    Other solutions could have been:
    - `simple_term_menu`: would be good as well for our use case but some issues suggest
      that Windows is less supported.
      See: https://github.com/IngoMeyer441/simple-term-menu
    - `PyInquirer`: very similar to `InquirerPy` but older and not maintained anymore.
      In particular, no support of Python3.10.
      See: https://github.com/CITGuru/PyInquirer
    - `pick` (or `pickpack`): easy to use and flexible but built on top of Python's
      standard library `curses` that is specific to Unix (not implemented on Windows).
      See https://github.com/wong2/pick and https://github.com/anafvana/pickpack.
    - `inquirer`: lot of traction (700 stars) but explicitly states "experimental
      support of Windows". Not built on top of `python-prompt-toolkit`.
      See https://github.com/magmax/python-inquirer

TODO: add support for `huggingface-cli delete-cache aaaaaa bbbbbb cccccc (...)` ?
TODO: add "--keep-last" arg to delete revisions that are not on `main` ref
TODO: add "--filter" arg to filter repositories by name ?
TODO: add "--limit" arg to limit to X repos ?
TODO: add "-y" arg for immediate deletion ?
See discussions in https://github.com/huggingface/huggingface_hub/issues/1025.
    N)	Namespace_SubParsersActionwraps)mkstemp)AnyCallableIterableListLiteralOptionalUnion   )CachedRepoInfoCachedRevisionInfoHFCacheInfoscan_cache_dir   )BaseHuggingfaceCLICommand)ANSI)inquirer)Choice)	SeparatorTFalphabeticallastUpdatedlastUsedsizefnreturnc                    s   t   fdd}|S )z4Decorator to flag methods that require `InquirerPy`.c                     s   t std | i |S )NzThe `delete-cache` command requires extra dependencies to work with the TUI.
Please run `pip install huggingface_hub[cli]` to install them.
Otherwise, disable TUI using the `--disable-tui` flag.)_inquirer_py_availableImportError)argskwargsr    y/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/huggingface_hub/commands/delete_cache.py_innerV   s
   z#require_inquirer_py.<locals>._innerr   )r   r'   r%   r$   r&   require_inquirer_pyR   s   
r(   CANCEL_DELETIONc                   @   s8   e Zd ZedefddZdeddfddZd	d
 ZdS )DeleteCacheCommandparserc                 C   sV   | j ddd}|jdtd dd |jddd	d
 |jddg ddd |jtd d S )Nzdelete-cachez*Delete revisions from the cache directory.)helpz--dirzEcache directory (optional). Default to the default HuggingFace cache.)typedefaultr,   z--disable-tui
store_truezrDisable Terminal User Interface (TUI) mode. Useful if your platform/terminal doesn't support the multiselect menu.)actionr,   z--sort?r   zSort repositories by the specified criteria. Options: 'alphabetical' (A-Z), 'lastUpdated' (newest first), 'lastUsed' (most recent first), 'size' (largest first).)nargschoicesr,   )func)
add_parseradd_argumentstrset_defaultsr*   )r+   delete_cache_parserr%   r%   r&   register_subcommandi   s&   	z&DeleteCacheCommand.register_subcommandr"   r   Nc                 C   s   |j | _|j| _|j| _d S N)dir	cache_dirdisable_tuisortsort_by)selfr"   r%   r%   r&   __init__   s   zDeleteCacheCommand.__init__c                 C   s   t | j}| jrt|g | jd}nt|g | jd}t|dkr\t|vr\t||d }| jr2t	|}nt
|}|r\|j| }td |  tdt|j dt|j d|j d d	S td
 d	S )z/Run `delete-cache` command with or without TUI.)preselectedr@   r   z Confirm deletion ?zStart deletion.zDone. Deleted z repo(s) and z revision(s) for a total of .Nz"Deletion is cancelled. Do nothing.)r   r=   r>   _manual_review_no_tuir@   _manual_review_tuilen_CANCEL_DELETION_STR_get_expectations_str_ask_for_confirmation_no_tui_ask_for_confirmation_tuidelete_revisionsprintexecuterepos	snapshotsexpected_freed_size_str)rA   hf_cache_infoselected_hashesconfirm_message	confirmedstrategyr%   r%   r&   run   s,   


zDeleteCacheCommand.run)	__name__
__module____qualname__staticmethodr   r:   r   rB   rW   r%   r%   r%   r&   r*   h   s
    "r*   repor@   c                 C   sb   |dkr| j | j fS |dkrtdd | jD  S |dkr#| j S |dkr+| j S | j | jfS )Nr   r   c                 s   s    | ]}|j V  qd S r;   last_modified).0revr%   r%   r&   	<genexpr>   s    z(_get_repo_sorting_key.<locals>.<genexpr>r   r   )	repo_typerepo_idlowermax	revisionslast_accessedsize_on_disk)r\   r@   r%   r%   r&   _get_repo_sorting_key   s   ri   rR   rC   c              	      s   t j||d}tjd|ddtdd |D ddd	d
 d d fdd} jd d|i z  W S  tyA   g  Y S w )zzAsk the user for a manual review of the revisions to delete.

    Displays a multi-select menu in the terminal (TUI).
    )rO   rC   r@   zSelect revisions to delete:Fd   c                 S   s"   g | ]}t |tr|jr|jqS r%   )
isinstancer   enabledvalue)r_   cr%   r%   r&   
<listcomp>   s   " z&_manual_review_tui.<locals>.<listcomp>rS   zWPress <space> to select, <enter> to validate and <ctrl+c> to quit without modification.c                 S   s   t |  dS )Nz revision(s) selected.rG   )resultr%   r%   r&   <lambda>   s    z$_manual_review_tui.<locals>.<lambda>)messager3   cycleheightinstructionlong_instructiontransformerr   Nc                    s    t dd  jjD d _d S )Nc                 S   s   g | ]
}|d  r|d qS )rl   rm   r%   )r_   choicer%   r%   r&   ro          zD_manual_review_tui.<locals>._update_expectations.<locals>.<listcomp>rp   )rI   content_controlr3   _instruction)_checkboxrR   r%   r&   _update_expectations   s   z0_manual_review_tui.<locals>._update_expectationstoggler4   )r   N)	_get_tui_choices_from_scanrO   r   r   rI   kb_func_lookupappendrN   KeyboardInterrupt)rR   rC   r@   r3   r   r%   r   r&   rF      s0   
rF   rt   r.   c                 C   s   t j| |d S )z$Ask for confirmation using Inquirer.r.   )r   confirmrN   )rt   r.   r%   r%   r&   rK      s   rK   rO   c                    s   g }| ttddd t|  fddd}|D ]J}| td|j  d|j d	|j d
|j	 d	 t|j
tdD ]&}| t|j|jdd  ddt|jpSd d|j |j|v d q;q|S )a  Build a list of choices from the scanned repos.

    Args:
        repos (*Iterable[`CachedRepoInfo`]*):
            List of scanned repos on which we want to delete revisions.
        preselected (*List[`str`]*):
            List of revision hashes that will be preselected.
        sort_by (*Optional[SortingOption_T]*):
            Sorting direction. Choices: "alphabetical", "lastUpdated", "lastUsed", "size".

    Return:
        The list of choices to pass to `inquirer.checkbox`.
    z=None of the following (if selected, nothing will be deleted).F)namerl   c                    
   t |  S r;   ri   r\   r@   r%   r&   rs        
 z,_get_tui_choices_from_scan.<locals>.<lambda>key
  (, used )N   z: , 
(detached) # modified )r   r   rH   sortedr   rb   
capitalizerc   size_on_disk_strlast_accessed_strrf   _revision_sorting_ordercommit_hashjoinrefslast_modified_str)rO   rC   r@   r3   sorted_reposr\   revisionr%   r   r&   r      s>   	r   c                    sp  t dd\}}t| g }t| j fddd}|D ]E}|d|j  d|j d|j	 d	|j
 d
	 t|jtdD ]#}||j|v rGdnd d|j ddt|jpWd d|j  q<qt|d}	|	t |	d| W d   n1 s~w   Y  dt| d}
tddd |
 dD  	 t|}tt| |d ddrnqt| t|S )zAsk the user for a manual review of the revisions to delete.

    Used when TUI is disabled. Manual review happens in a separate tmp file that the
    user can manually edit.
    z.txt)suffixc                    r   r;   r   r   r   r%   r&   rs   G  r   z'_manual_review_no_tui.<locals>.<lambda>r   z
# r   r   r   r    #z    z	 # Refs: r   r   r   wr   Na*  
    TUI is disabled. In order to select which revisions you want to delete, please edit
    the following file using the text editor of your choice. Instructions for manual
    editing are located at the beginning of the file. Edit the file, save it and confirm
    to continue.
    File to edit: z
    c                 s   s    | ]}|  V  qd S r;   stripr_   liner%   r%   r&   ra   e  s    z(_manual_review_no_tui.<locals>.<genexpr>Tz Continue ?Fr   )r   oscloser   rO   r   rb   r   rc   r   r   rf   r   r   r   r   r   openwrite"_MANUAL_REVIEW_NO_TUI_INSTRUCTIONSr   boldrM   r   split_read_manual_review_tmp_filerJ   rI   remove)rR   rC   r@   fdtmp_pathlinesr   r\   r   finstructionsrS   r%   r   r&   rE   7  sN   

"
	rE   c                 C   sl   d}d}d}|| |f }| |rdnd }	 t | }||kr"|S ||v r(dS ||v r.dS td|  q)	z'Ask for confirmation using pure-python.)yyes1)nno0r   z (Y/n) z (y/N) TFzInvalid input. Must be one of )inputrd   rM   )rt   r.   YESNODEFAULTALLfull_messageanswerr%   r%   r&   rJ   u  s   rJ   rS   c                 C   s,   t |v rdS | j| }t| d|j dS )zFormat a string to display to the user how much space would be saved.

    Example:
    ```
    >>> _get_expectations_str(hf_cache_info, selected_hashes)
    '7 revisions selected counting for 4.3G.'
    ```
    zNothing will be deleted.z! revisions selected counting for rD   )rH   rL   rG   rQ   )rR   rS   rV   r%   r%   r&   rI     s   	
rI   r   c                 C   sn   t | }| }W d   n1 sw   Y  dd |dD }dd |D }dd |D }dd |D S )a  Read the manually reviewed instruction file and return a list of revision hash.

    Example:
        ```txt
        # This is the tmp file content
        ###

        # Commented out line
        123456789 # revision hash

        # Something else
        #      a_newer_hash # 2 days ago
            an_older_hash # 3 days ago
        ```

        ```py
        >>> _read_manual_review_tmp_file(tmp_path)
        ['123456789', 'an_older_hash']
        ```
    Nc                 S   s   g | ]}|  qS r%   r   r   r%   r%   r&   ro     s    z0_read_manual_review_tmp_file.<locals>.<listcomp>r   c                 S   s   g | ]	}| d s|qS )r   )
startswithr   r%   r%   r&   ro     s    c                 S   s   g | ]}| d d  qS )r   r   )r   r   r   r%   r%   r&   ro     s    c                 S   s   g | ]
}t |d kr|qS )r   rq   )r_   hashr%   r%   r&   ro     r{   )r   readr   )r   r   contentr   selected_linesrS   r%   r%   r&   r     s   

r   a  
# INSTRUCTIONS
# ------------
# This is a temporary file created by running `huggingface-cli delete-cache` with the
# `--disable-tui` option. It contains a set of revisions that can be deleted from your
# local cache directory.
#
# Please manually review the revisions you want to delete:
#   - Revision hashes can be commented out with '#'.
#   - Only non-commented revisions in this file will be deleted.
#   - Revision hashes that are removed from this file are ignored as well.
#   - If `aa  ` line is uncommented, the all cache deletion is cancelled and
#     no changes will be applied.
#
# Once you've manually reviewed this file, please confirm deletion in the terminal. This
# file will be automatically removed once done.
# ------------

# KILL SWITCH
# ------------
# Un-comment following line to completely cancel the deletion process
# z,
# ------------

# REVISIONS
# ------------
r   c                 C   s   | j S r;   r]   )r   r%   r%   r&   r     s   r   r;   )T)3__doc__r   argparser   r   	functoolsr   tempfiler   typingr   r   r	   r
   r   r   r   utilsr   r   r   r   r   r   
_cli_utilsr   
InquirerPyr   InquirerPy.base.controlr   InquirerPy.separatorr   r    r!   SortingOption_Tr(   rH   r*   ri   r7   rF   boolrK   r   rE   rJ   rI   r   r   r   r   r%   r%   r%   r&   <module>   s   ,$N3
=
>%