U
    ”Ê¹jÕ  ã                   @   sú  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 d dlm	Z	 d dl
mZmZmZmZmZmZmZ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!m"Z"m#Z#m$Z$m%Z% ddl&m'Z' e" (e)¡Z*G dd„ dƒZ+ee,e	f e-dœdd„Z.ee,e	f e,e-dœdd„Z/ee,e	f e-dœdd„Z0ee,e	f e-dœdd„Z1ee,e	f e-dœdd„Z2d+e,ee,e	df ee, dœdd„Z3ee,e	f e-dœd d!„Z4d,ee,e	f ee, e5d"œd#d$„Z6G d%d&„ d&eƒZ7ed'd(„ ƒZ8G d)d*„ d*ƒZ9dS )-é    N)Úcontextmanager)ÚPath)ÚCallableÚDictÚIteratorÚListÚOptionalÚTupleÚ	TypedDictÚUnion)Úurlparse)Ú	constants)Úmetadata_loadÚmetadata_saveé   )ÚHfApiÚrepo_type_and_id_from_hf_id)ÚLFS_MULTIPART_UPLOAD_COMMAND)ÚSoftTemporaryDirectoryÚ	get_tokenÚloggingÚrun_subprocessÚtqdmÚvalidate_hf_hub_args)Ú_deprecate_methodc                   @   s�   e Zd ZdZdeeeejee dœdd„Z	e
edœdd„ƒZe
edœd	d
„ƒZe
edœdd„ƒZe
edœdd„ƒZe
edœdd„ƒZdd„ ZdS )ÚCommandInProgressz=
    Utility to follow commands launched asynchronously.
    N)ÚtitleÚis_done_methodÚstatus_methodÚprocessÚpost_methodc                 C   s.   || _ || _|| _|| _d| _d| _|| _d S )NÚ )r   Ú_is_doneÚ_statusÚ_processÚ_stderrÚ_stdoutÚ_post_method)Úselfr   r   r   r   r    © r)   úY/var/www/html/bwave/python/venv/lib/python3.8/site-packages/huggingface_hub/repository.pyÚ__init__$   s    zCommandInProgress.__init__©Úreturnc                 C   s(   |   ¡ }|r$| jdk	r$|  ¡  d| _|S )z.
        Whether the process is done.
        N)r"   r'   )r(   Úresultr)   r)   r*   Úis_done4   s
    zCommandInProgress.is_donec                 C   s   |   ¡ S )zü
        The exit code/status of the current action. Will return `0` if the
        command has completed successfully, and a number between 1 and 255 if
        the process errored-out.

        Will return -1 if the command is still ongoing.
        )r#   ©r(   r)   r)   r*   ÚstatusA   s    	zCommandInProgress.statusc                 C   s
   | j dkS )z2
        Whether the process errored-out.
        r   ©r1   r0   r)   r)   r*   ÚfailedL   s    zCommandInProgress.failedc                 C   s(   | j jdk	r"|  j| j j ¡ 7  _| jS )zC
        The current output message on the standard error.
        N)r$   Ústderrr%   Úreadr0   r)   r)   r*   r4   S   s    zCommandInProgress.stderrc                 C   s(   | j jdk	r"|  j| j j ¡ 7  _| jS )zD
        The current output message on the standard output.
        N)r$   Ústdoutr&   r5   r0   r)   r)   r*   r6   \   s    zCommandInProgress.stdoutc              	   C   s@   | j }|dkrd}d| j› d|› d| js,dnd› d| jj› d	�	S )
NéÿÿÿÿÚrunningú[z command, status code: z, zin progress.z	finished.z PID: ú])r1   r   r/   r$   Úpid)r(   r1   r)   r)   r*   Ú__repr__e   s
    ,ÿzCommandInProgress.__repr__)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ústrr   Ú
subprocessÚPopenr   r+   ÚpropertyÚboolr/   Úintr1   r3   r4   r6   r<   r)   r)   r)   r*   r      s(   
 úú
r   )Úfolderr-   c                 C   s>   t j t j | d¡¡}tjd ¡ | tjtjd�}|o<|jdkS )a  
    Check if the folder is the root or part of a git repository

    Args:
        folder (`str`):
            The folder in which to run the command.

    Returns:
        `bool`: `True` if the repository is part of a repository, `False`
        otherwise.
    z.gitz
git branch)Úcwdr6   r4   r   )	ÚosÚpathÚexistsÚjoinrB   ÚrunÚsplitÚPIPEÚ
returncode)rG   Zfolder_existsZ
git_branchr)   r)   r*   Úis_git_repor   s    rQ   )rG   Ú
remote_urlr-   c                 C   s@   t | ƒsdS td| ƒj}t dd|¡}dd„ | ¡ D ƒ}||kS )am  
    Check if the folder is a local clone of the remote_url

    Args:
        folder (`str` or `Path`):
            The folder in which to run the command.
        remote_url (`str`):
            The url of a git repository.

    Returns:
        `bool`: `True` if the repository is a local clone of the remote
        repository specified, `False` otherwise.
    Fzgit remote -vúhttps://.*@úhttps://c                 S   s   g | ]}t  d d|¡‘qS )rS   rT   )ÚreÚsub)Ú.0Úremoter)   r)   r*   Ú
<listcomp>˜   s     z"is_local_clone.<locals>.<listcomp>)rQ   r   r6   rU   rV   rN   )rG   rR   Úremotesr)   r)   r*   Úis_local_cloneƒ   s    r[   )Úfilenamer-   c              
   C   sÖ   t | ƒj}t | ƒj} z"td ¡ | g |ƒ}|j ¡ }W n@ tjk
rv } z t	|ƒs\W Y ¢dS t
|jƒ‚W 5 d}~X Y nX t|ƒdkrˆdS ddddœ}| d¡D ]*}| ¡ D ]}||krªd|krªd||< qªqžt| ¡ ƒS )	zù
    Check if the file passed is tracked with git-lfs.

    Args:
        filename (`str` or `Path`):
            The filename to check.

    Returns:
        `bool`: `True` if the file passed is tracked with git-lfs, `False`
        otherwise.
    zgit check-attr -aFNr   )ÚdiffÚmergeÚfilterÚ
ÚlfsT)r   ÚparentÚnamer   rN   r6   ÚstriprB   ÚCalledProcessErrorrQ   ÚOSErrorr4   ÚlenÚkeysÚallÚvalues)r\   rG   ÚpÚ
attributesÚexcZfound_lfs_tagÚ	attributeÚtagr)   r)   r*   Úis_tracked_with_lfsœ   s"    


rp   c              
   C   sp   t | ƒj}t | ƒj} z(td ¡ | g |dd�}t|jƒ }W n. tjk
rj } zt	|j
ƒ‚W 5 d}~X Y nX |S )a  
    Check if file is git-ignored. Supports nested .gitignore files.

    Args:
        filename (`str` or `Path`):
            The filename to check.

    Returns:
        `bool`: `True` if the file passed is ignored by `git`, `False`
        otherwise.
    zgit check-ignoreF©ÚcheckN)r   rb   rc   r   rN   rE   rP   rB   re   rf   r4   )r\   rG   rk   Z
is_ignoredrm   r)   r)   r*   Úis_git_ignoredÁ   s    

rs   c              	   C   sx   z\t | dƒ�}| d¡}W 5 Q R X tddddddd	httd
dƒƒdh B ƒ}t| d|¡ƒW S  tk
rr   Y dS X dS )zØ
    Check if file is a binary file.

    Args:
        filename (`str` or `Path`):
            The filename to check.

    Returns:
        `bool`: `True` if the file passed is a binary file, `False` otherwise.
    Úrbi    é   é   é	   é
   é   é   é   é    é   é   NT)Úopenr5   Ú	bytearrayÚsetÚrangerE   Ú	translateÚUnicodeDecodeError)r\   ÚfÚcontentZ
text_charsr)   r)   r*   Úis_binary_fileÚ   s    *r‡   Ú.)ÚpatternrG   r-   c              
   C   sp   z<t d ¡ | g |ƒ}t|j ¡ ƒr6|j ¡  d¡}ng }W n. tjk
rj } zt|jƒ‚W 5 d}~X Y nX |S )aQ  
    Returns a list of filenames that are to be staged.

    Args:
        pattern (`str` or `Path`):
            The pattern of filenames to check. Put `.` to get all files.
        folder (`str` or `Path`):
            The folder in which to run the command.

    Returns:
        `List[str]`: List of files that are to be staged.
    z#git ls-files --exclude-standard -mor`   N)	r   rN   rg   r6   rd   rB   re   ÚEnvironmentErrorr4   )r‰   rG   rk   Úfilesrm   r)   r)   r*   Úfiles_to_be_stagedñ   s    rŒ   c              
   C   sR   zt d| ƒ W dS  tjk
rL } zd|jkr6tdƒ‚W Y ¢dS d}~X Y nX dS )a  
    Check if the current checked-out branch is tracked upstream.

    Args:
        folder (`str` or `Path`):
            The folder in which to run the command.

    Returns:
        `bool`: `True` if the current checked-out branch is tracked upstream,
        `False` otherwise.
    z4git rev-parse --symbolic-full-name --abbrev-ref @{u}TÚHEADzNo branch checked outFN)r   rB   re   r4   rf   )rG   rm   r)   r)   r*   Úis_tracked_upstream
  s    

rŽ   )rG   Úupstreamr-   c              
   C   s^   z*t d|pd› �| ƒ}t|j d¡ƒd W S  tjk
rX } zt|jƒ‚W 5 d}~X Y nX dS )a³  
        Check the number of commits that would be pushed upstream

        Args:
            folder (`str` or `Path`):
                The folder in which to run the command.
            upstream (`str`, *optional*):
    The name of the upstream repository with which the comparison should be
    made.

        Returns:
            `int`: Number of commits that would be pushed upstream were a `git
            push` to proceed.
    zgit cherry -v r!   r`   r   N)r   rg   r6   rN   rB   re   rŠ   r4   )rG   r�   r.   rm   r)   r)   r*   Úcommits_to_push   s
    r�   c                   @   s   e Zd ZU eed< eed< dS )ÚPbarTÚbarÚ
past_bytesN)r=   r>   r?   r   Ú__annotations__rF   r)   r)   r)   r*   r‘   6  s   
r‘   c               
   c   sÚ   t  ¡ tjkr2z
dV  W n tk
r,   Y nX dS tjdœdd„} tj 	dd¡}t
ƒ �z}tj |d¡tjd< t  dtjd › �¡ t ¡ }tj| |fd	d
�}| ¡  z
dV  W 5 | ¡  | ¡  |tjd< X W 5 Q R X dS )zv
    This is a context manager that will log the Git LFS progress of cleaning,
    smudging, pulling and pushing.
    N)Ústopping_eventc                    sH  i ‰‡fdd„‰ t t dœ‡ ‡fdd„}tj tjd ¡sXˆ ¡ rLˆ ƒ  dS t d¡ q(|tjd ƒD ]Ü}z| 	¡ \}}}}W n2 t
k
r° } zt
d	|› �ƒ|‚W 5 d}~X Y nX | ¡ › d
|› �}| 	d¡\}	}
t|	ƒ}t|
ƒ}ˆ ||f¡}|dk�r$t|||ddddd�t|	ƒdœˆ||f< qf|d  ||d  ¡ ||d< qfdS )zl
        To be launched as a separate thread with an event meaning it should stop
        the tail.
        c                     sF   ˆ   ¡ D ]8} | d  | d j| d  ¡ | d  ¡  | d  ¡  qd S )Nr’   r“   )rj   ÚupdateÚtotalÚrefreshÚclose)Úpbar)Úpbarsr)   r*   Úclose_pbarsR  s    z?_lfs_log_progress.<locals>.output_progress.<locals>.close_pbarsr,   c              	   3   sx   t | dƒ�d}d}ˆ ¡ r ˆ ƒ  qj| ¡ }|dk	r^t| ¡ ƒdks^||7 }| d¡rh|V  d}qt d¡ qW 5 Q R X dS )z¾
            Creates a generator to be iterated through, which will return each
            line one by one. Will stop tailing the file if the stopping_event is
            set.
            Úrr!   Nr   r`   r   )r   Úis_setÚreadlinerg   rd   ÚendswithÚtimeÚsleep)r\   ÚfileÚcurrent_lineZline_bit)rœ   r•   r)   r*   Ú	tail_fileX  s    
z=_lfs_log_progress.<locals>.output_progress.<locals>.tail_fileÚGIT_LFS_PROGRESSNé   z!Cannot unpack LFS progress line:
z file ú/ÚBTi   zhuggingface_hub.lfs_upload)ÚdescÚinitialr—   ÚunitZ
unit_scaleZunit_divisorrc   )r’   r“   r’   r“   )r   rA   rI   rJ   rK   Úenvironrž   r¡   r¢   rN   Ú
ValueErrorÚ
capitalizerF   Úgetr   r–   )r•   r¥   ÚlineÚstateZfile_progressZbyte_progressr\   ÚerrorÚdescriptionZcurrent_bytesÚtotal_bytesZcurrent_bytes_intZtotal_bytes_intrš   r)   )rœ   r›   r•   r*   Úoutput_progressJ  s@    "
ù	öz*_lfs_log_progress.<locals>.output_progressr¦   r!   Zlfs_progresszFollowing progress in T)ÚtargetÚargsÚdaemon)ÚloggerÚgetEffectiveLevelr   ÚERRORÚ	ExceptionÚ	threadingÚEventrI   r­   r°   r   rJ   rL   ÚdebugÚThreadÚstartr�   )r¶   Zcurrent_lfs_progress_valueZtmpdirZ
exit_eventÚxr)   r)   r*   Ú_lfs_log_progress<  s&    
M
rÄ   c                   @   sÚ  e Zd ZU dZee ed< eeddd�d\e	e
ef ee
 ee
 e	ee
f ee
 ee
 ee
 eee d	œ	d
d„ƒƒZee
dœdd„ƒZdd„ Zed]e
e	ee
df dœdd„ƒZd^ee
 ee
 dœdd„Zdd„ Ze
dœdd„Ze
dœdd„Ze
dœdd„Zee
 dœdd „Zd_e	e
ee
 f ed!œd"d#„Ze	e
ee
 f d$œd%d&„Zd'd(„ Zd`e
ee
 d*œd+d,„Zdae
ee
 d*œd-d.„Zdbd/d0„Zdceed1œd2d3„Z dde
ed4œd5d6„Z!dee
d8œd9d:„Z"dfee
 eee	e
e#e
ef f d;œd<d=„Z$dge
ed>œd?d@„Z%dhe
ee
 edAœdBdC„Z&die
ee
 edAœdDdE„Z'dje
ee
 ee
 dFœdGdH„Z(edœdIdJ„Z)dke
eeee	de
e#e
ef f dKœdLdM„Z*e+dle
ee
 eeedNœdOdP„ƒZ,ee- dœdQdR„Z.e-ddSœdTdU„Z/edVdW„ ƒZ0edXdY„ ƒZ1dZd[„ Z2dS )mÚ
RepositoryaE  
    Helper class to wrap the git and git-lfs commands.

    The aim is to facilitate interacting with huggingface.co hosted model or
    dataset repos, though not a lot here (if any) is actually specific to
    huggingface.co.

    > [!WARNING]
    > [`Repository`] is deprecated in favor of the http-based alternatives implemented in
    > [`HfApi`]. Given its large adoption in legacy code, the complete removal of
    > [`Repository`] will only happen in release `v1.0`. For more details, please read
    > https://huggingface.co/docs/huggingface_hub/concepts/git_vs_http.
    Úcommand_queuez1.0z÷Please prefer the http-based alternatives instead. Given its large adoption in legacy code, the complete removal is only planned on next major release.
For more details, please read https://huggingface.co/docs/huggingface_hub/concepts/git_vs_http.)ÚversionÚmessageNTF)	Ú	local_dirÚ
clone_fromÚ	repo_typeÚtokenÚgit_userÚ	git_emailÚrevisionÚskip_lfs_filesÚclientc
                 C   sj  t |tƒrt|ƒ}tj|dd� tj t ¡ |¡| _|| _	g | _
|| _|	dk	rR|	ntƒ | _|  ¡  t |tƒrt|| _n|dkr„d| _ntƒ | _|dk	r¢| j|d� nt| jƒr¸t d¡ ntdƒ‚| jdk	�r|dksÞ|dk�r| j | j¡}
|dkrþ|
 d¡}|dk�r|
 d	¡}|dk	�s&|dk	�r2|  ||¡ |  ¡  |  ¡  |dk	�rZ| j|dd
� t | j¡ dS )aÈ	  
        Instantiate a local clone of a git repo.

        If `clone_from` is set, the repo will be cloned from an existing remote repository.
        If the remote repo does not exist, a `EnvironmentError` exception will be thrown.
        Please create the remote repo first using [`create_repo`].

        `Repository` uses the local git credentials by default. If explicitly set, the `token`
        or the `git_user`/`git_email` pair will be used instead.

        Args:
            local_dir (`str` or `Path`):
                path (e.g. `'my_trained_model/'`) to the local directory, where
                the `Repository` will be initialized.
            clone_from (`str`, *optional*):
                Either a repository url or `repo_id`.
                Example:
                - `"https://huggingface.co/philschmid/playground-tests"`
                - `"philschmid/playground-tests"`
            repo_type (`str`, *optional*):
                To set when cloning a repo from a repo_id. Default is model.
            token (`bool` or `str`, *optional*):
                A valid authentication token (see https://huggingface.co/settings/token).
                If `None` or `True` and machine is logged in (through `hf auth login`
                or [`~huggingface_hub.login`]), token will be retrieved from the cache.
                If `False`, token is not sent in the request header.
            git_user (`str`, *optional*):
                will override the `git config user.name` for committing and
                pushing files to the hub.
            git_email (`str`, *optional*):
                will override the `git config user.email` for committing and
                pushing files to the hub.
            revision (`str`, *optional*):
                Revision to checkout after initializing the repository. If the
                revision doesn't exist, a branch will be created with that
                revision name from the default branch's current HEAD.
            skip_lfs_files (`bool`, *optional*, defaults to `False`):
                whether to skip git-LFS files or not.
            client (`HfApi`, *optional*):
                Instance of [`HfApi`] to use when calling the HF Hub API. A new
                instance will be created if this is left to `None`.

        Raises:
            [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
                If the remote repository set in `clone_from` does not exist.
        T)Úexist_okNF)Úrepo_urlz [Repository] is a valid git repozNIf not specifying `clone_from`, you need to pass Repository a valid git clone.ÚemailÚfullname©Úcreate_branch_ok)Ú
isinstancer   rA   rI   ÚmakedirsrJ   rL   ÚgetcwdrÉ   Ú
_repo_typerÆ   rÐ   r   rÑ   Úcheck_git_versionsÚhuggingface_tokenr   rÊ   rQ   rº   rÀ   r®   Zwhoamir°   Úgit_config_username_and_emailÚlfs_enable_largefilesÚgit_credential_helper_storeÚgit_checkoutÚatexitÚregisterÚwait_for_commands)r(   rÉ   rÊ   rË   rÌ   rÍ   rÎ   rÏ   rÐ   rÑ   Úuserr)   r)   r*   r+   »  s@    C






zRepository.__init__r,   c              
   C   sJ   zt d| jƒj ¡ }W n. tjk
rD } zt|jƒ‚W 5 d}~X Y nX |S )zz
        Returns the current checked out branch.

        Returns:
            `str`: Current checked out branch.
        zgit rev-parse --abbrev-ref HEADN©r   rÉ   r6   rd   rB   re   rŠ   r4   )r(   r.   rm   r)   r)   r*   Úcurrent_branch0  s
    zRepository.current_branchc                 C   s~   zt d| jƒj ¡ }W n tk
r2   tdƒ‚Y nX zt d| jƒj ¡ }W n tk
rf   tdƒ‚Y nX t |d | ¡ dS )zì
        Checks that `git` and `git-lfs` can be run.

        Raises:
            [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
                If `git` or `git-lfs` are not installed.
        zgit --versionz9Looks like you do not have git installed, please install.zgit-lfs --versionz«Looks like you do not have git-lfs installed, please install. You can install from https://git-lfs.github.com/. Then run `git lfs install` (you only have to do this once).r`   N)r   rÉ   r6   rd   ÚFileNotFoundErrorrŠ   rº   Úinfo)r(   Zgit_versionZlfs_versionr)   r)   r*   rÜ   ?  s    ÿ
zRepository.check_git_versions)rÓ   rÌ   c              
   C   sv  t |tƒr|n|dkrdn| j}|dk	r:| d¡r:tdƒ‚| jj}||ksdd|krút| d¡ƒdkrút	||d�\}}}|dk	rŒ|› d|› �n|}|dk	rž|| _
|d }| j
tjkrÂ|tj| j
 7 }|dk	ròt|ƒj}| |› d	�|› d
|› d�¡}||7 }t dd|¡}	�z6td| jƒ tt | j¡ƒdk�rœt d|	› d�¡ tƒ �N tj ¡ }
| j�rh|
 ddi¡ t| j�rvdnd› d|› d�| j|
d� W 5 Q R X n¢t| jƒ�sÂtd| j› d| j› d�ƒ‚t| j|ƒ�rêt | j› d|	› d�¡ nTtd| jdd�}d |	› d!|	› d"�}|j dk�r6t d#d$|j!¡}|d%|› �7 }t|ƒ‚W n0 t"j#k
�rp } zt|j$ƒ‚W 5 d}~X Y nX dS )&a­  
        Clone from a remote. If the folder already exists, will try to clone the
        repository within it.

        If this folder is a git repository with linked history, will try to
        update the repository.

        Args:
            repo_url (`str`):
                The URL from which to clone the repository
            token (`Union[str, bool]`, *optional*):
                Whether to use the authentication token. It can be:
                 - a string which is the token itself
                 - `False`, which would not use the authentication token
                 - `True`, which would fetch the authentication token from the
                   local folder and use it (you should be logged in for this to
                   work).
                - `None`, which would retrieve the value of
                  `self.huggingface_token`.

        > [!TIP]
        > Raises the following error:
        >
        >     - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
        >       if an organization token (starts with "api_org") is passed. Use must use
        >       your own personal access token (see https://hf.co/settings/tokens).
        >
        >     - [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
        >       if you are trying to clone the repository in a non-empty folder, or if the
        >       `git` operations raise errors.
        FNZapi_orgzgYou must use your personal access token, not an Organization token (see https://hf.co/settings/tokens).Úhttpr¨   r§   )Úhub_urlz://z://user:ú@z(https?)://.*@z\1://zgit lfs installr   zCloning z into local empty directory.ZGIT_LFS_SKIP_SMUDGEÚ1z	git clonezgit lfs cloneú z .)ÚenvzPTried to clone a repository in a non-empty folder that isn't a git repository ('z7'). If you really want to do this, do it manually:
 cd z‹ && git init && git remote add origin && git pull origin main
 or clone repo to a new folder and move your existing files there afterwards.z is already a clone of z?. Make sure you pull the latest changes with `repo.git_pull()`.zgit remote get-url originrq   zTried to clone zn in an unrelated git repository.
If you believe this is an error, please add a remote with the following URL: rˆ   rS   rT   z'
Local path has its origin defined as: )%rØ   rA   rÝ   Ú
startswithr®   rÑ   Zendpointrg   rN   r   rÛ   r   ZREPO_TYPES_URL_PREFIXESr   ÚschemeÚreplacerU   rV   r   rÉ   rI   Úlistdirrº   ÚwarningrÄ   r­   ÚcopyrÐ   r–   rQ   rŠ   r[   rP   r6   rB   re   r4   )r(   rÓ   rÌ   rë   rË   Ú	namespaceÚ	repo_nameZrepo_idrñ   Zclean_repo_urlrï   ÚoutputÚ	error_msgZclean_local_remote_urlrm   r)   r)   r*   rÊ   V  sl    #ÿÿú	ÿ"

ú
ÿ	ÿÿzRepository.clone_from)rÍ   rÎ   c              
   C   st   z@|dk	r t d ¡ |g | jƒ |dk	r>t d|› � ¡ | jƒ W n. tjk
rn } zt|jƒ‚W 5 d}~X Y nX dS )a  
        Sets git username and email (only in the current repo).

        Args:
            git_user (`str`, *optional*):
                The username to register through `git`.
            git_email (`str`, *optional*):
                The email to register through `git`.
        Nzgit config user.namezgit config user.email )r   rN   rÉ   rB   re   rŠ   r4   )r(   rÍ   rÎ   rm   r)   r)   r*   rÞ   Ó  s    
z(Repository.git_config_username_and_emailc              
   C   sD   zt d| jƒ W n. tjk
r> } zt|jƒ‚W 5 d}~X Y nX dS )z;
        Sets the git credential helper to `store`
        z"git config credential.helper storeN)r   rÉ   rB   re   rŠ   r4   )r(   rm   r)   r)   r*   rà   æ  s    z&Repository.git_credential_helper_storec              
   C   sL   zt d| jƒ}|j ¡ W S  tjk
rF } zt|jƒ‚W 5 d}~X Y nX dS )zy
        Get commit sha on top of HEAD.

        Returns:
            `str`: The current checked out commit SHA.
        zgit rev-parse HEADNræ   )r(   rk   rm   r)   r)   r*   Úgit_head_hashï  s
    zRepository.git_head_hashc              
   C   sZ   z&t d| jƒ}|j ¡ }t dd|¡W S  tjk
rT } zt|j	ƒ‚W 5 d}~X Y nX dS )zp
        Get URL to origin remote.

        Returns:
            `str`: The URL of the `origin` remote.
        z"git config --get remote.origin.urlrS   rT   N)
r   rÉ   r6   rd   rU   rV   rB   re   rŠ   r4   )r(   rk   Úurlrm   r)   r)   r*   Úgit_remote_urlü  s    
zRepository.git_remote_urlc                 C   s4   |   ¡ }|  ¡ }| d¡r&|dd… }|› d|› �S )zæ
        Get URL to last commit on HEAD. We assume it's been pushed, and the url
        scheme is the same one as for GitHub or HuggingFace.

        Returns:
            `str`: The URL to the current checked-out commit.
        r¨   Nr7   z/commit/)rú   rü   r    )r(   Úsharû   r)   r)   r*   Úgit_head_commit_url  s
    
zRepository.git_head_commit_urlc              
   C   sŠ   zt d| jƒj ¡ }W n. tjk
rD } zt|jƒ‚W 5 d}~X Y nX t|ƒdkrVg S dd„ | 	d¡D ƒ}dd„ |D ƒ}dd„ |D ƒ}|S )	zê
        Returns a list of the files that are deleted in the working directory or
        index.

        Returns:
            `List[str]`: A list of files that have been deleted in the working
            directory or index.
        zgit status -sNr   c                 S   s   g | ]}|  ¡ ‘qS r)   )rd   ©rW   r1   r)   r)   r*   rY   2  s     z1Repository.list_deleted_files.<locals>.<listcomp>r`   c                 S   s    g | ]}d |  ¡ d kr|‘qS )ÚDr   )rN   rÿ   r)   r)   r*   rY   5  s      c                 S   s   g | ]}|  ¡ d   ¡ ‘qS )r7   )rN   rd   rÿ   r)   r)   r*   rY   8  s     ©
r   rÉ   r6   rd   rB   re   rŠ   r4   rg   rN   )r(   Ú
git_statusrm   Zmodified_files_statusesZdeleted_files_statusesÚdeleted_filesr)   r)   r*   Úlist_deleted_files  s    	
zRepository.list_deleted_files)Úpatternsr\   c              
   C   sr   t |tƒr|g}z.|D ]$}td|r&dnd› d|› �| jƒ qW n. tjk
rl } zt|jƒ‚W 5 d}~X Y nX dS )a9  
        Tell git-lfs to track files according to a pattern.

        Setting the `filename` argument to `True` will treat the arguments as
        literal filenames, not as patterns. Any special glob characters in the
        filename will be escaped when writing to the `.gitattributes` file.

        Args:
            patterns (`Union[str, List[str]]`):
                The pattern, or list of patterns, to track with git-lfs.
            filename (`bool`, *optional*, defaults to `False`):
                Whether to use the patterns as literal filenames.
        zgit lfs track z
--filenamer!   rî   N)rØ   rA   r   rÉ   rB   re   rŠ   r4   )r(   r  r\   r‰   rm   r)   r)   r*   Ú	lfs_track<  s    
þ
zRepository.lfs_track)r  c              
   C   sh   t |tƒr|g}z$|D ]}td ¡ |g | jƒ qW n. tjk
rb } zt|jƒ‚W 5 d}~X Y nX dS )zÀ
        Tell git-lfs to untrack those files.

        Args:
            patterns (`Union[str, List[str]]`):
                The pattern, or list of patterns, to untrack with git-lfs.
        zgit lfs untrackN)	rØ   rA   r   rN   rÉ   rB   re   rŠ   r4   )r(   r  r‰   rm   r)   r)   r*   Úlfs_untrackU  s    
zRepository.lfs_untrackc              
   C   sd   z0d}t |› d�| jƒ t |› dt› �| jƒ W n. tjk
r^ } zt|jƒ‚W 5 d}~X Y nX dS )zI
        HF-specific. This enables upload support of files >5GB.
        z'git config lfs.customtransfer.multipartz.path hfz.args N)r   rÉ   r   rB   re   rŠ   r4   )r(   Z
lfs_configrm   r)   r)   r*   rß   e  s    þz Repository.lfs_enable_largefilesrˆ   )r‰   r-   c                 C   s    g }|   ¡ }t|| jd�D ]v}||kr(qtj t ¡ | j|¡}t|ƒst|ƒstj 	|¡d }|dkrpt
 d¡ t|ƒ}|r|  |¡ | |¡ q|  |¡ |S )aH  
        Automatically track binary files with git-lfs.

        Args:
            pattern (`str`, *optional*, defaults to "."):
                The pattern with which to track files that are binary.

        Returns:
            `List[str]`: List of filenames that are now tracked due to being
            binary files
        ©rG   é   rx   z¨Parsing a large file to check if binary or not. Tracking large files using `repository.auto_track_large_files` is recommended so as to not load the full file in memory.)r  rŒ   rÉ   rI   rJ   rL   rÚ   rp   rs   Úgetsizerº   rô   r‡   r  Úappendr  )r(   r‰   Úfiles_to_be_tracked_with_lfsr  r\   Úpath_to_fileÚ
size_in_mbZ	is_binaryr)   r)   r*   Úauto_track_binary_filess  s$    ÿ

z"Repository.auto_track_binary_filesc                 C   sŠ   g }|   ¡ }t|| jd�D ]`}||kr(qtj t ¡ | j|¡}tj |¡d }|dkrt|ƒst	|ƒs|  
|¡ | |¡ q|  |¡ |S )ap  
        Automatically track large files (files that weigh more than 10MBs) with
        git-lfs.

        Args:
            pattern (`str`, *optional*, defaults to "."):
                The pattern with which to track files that are above 10MBs.

        Returns:
            `List[str]`: List of filenames that are now tracked due to their
            size.
        r  r	  rx   )r  rŒ   rÉ   rI   rJ   rL   rÚ   r
  rp   rs   r  r  r  )r(   r‰   r  r  r\   r  r  r)   r)   r*   Úauto_track_large_filesž  s    

z!Repository.auto_track_large_filesc              
   C   sp   z<t ƒ �, td|rdnd› �| jƒ}t |j¡ W 5 Q R X W n. tjk
rj } zt|j	ƒ‚W 5 d}~X Y nX dS )aŸ  
        git lfs prune

        Args:
            recent (`bool`, *optional*, defaults to `False`):
                Whether to prune files even if they were referenced by recent
                commits. See the following
                [link](https://github.com/git-lfs/git-lfs/blob/f3d43f0428a84fc4f1e5405b76b5a73ec2437e65/docs/man/git-lfs-prune.1.ronn#recent-files)
                for more information.
        zgit lfs prune z--recentr!   N©
rÄ   r   rÉ   rº   ré   r6   rB   re   rŠ   r4   )r(   Zrecentr.   rm   r)   r)   r*   Ú	lfs_prune¿  s    zRepository.lfs_prune)Úrebasera   c              
   C   sz   |sdnd}|r|d7 }z.t ƒ � t|| jƒ}t |j¡ W 5 Q R X W n. tjk
rt } zt|j	ƒ‚W 5 d}~X Y nX dS )a7  
        git pull

        Args:
            rebase (`bool`, *optional*, defaults to `False`):
                Whether to rebase the current branch on top of the upstream
                branch after fetching.
            lfs (`bool`, *optional*, defaults to `False`):
                Whether to fetch the LFS files too. This option only changes the
                behavior when a repository was cloned without fetching the LFS
                files; calling `repo.git_pull(lfs=True)` will then fetch the LFS
                file from the remote repository.
        zgit pullzgit lfs pullz	 --rebaseNr  )r(   r  ra   Úcommandr.   rm   r)   r)   r*   Úgit_pullÑ  s    zRepository.git_pull)r‰   Úauto_lfs_trackc              
   C   s–   |r4|   |¡}| |  |¡¡ |r4t d|› d�¡ z.td ¡ |g | jƒ}t d|j	› d�¡ W n. t
jk
r� } zt|jƒ‚W 5 d}~X Y nX dS )a7  
        git add

        Setting the `auto_lfs_track` parameter to `True` will automatically
        track files that are larger than 10MB with `git-lfs`.

        Args:
            pattern (`str`, *optional*, defaults to "."):
                The pattern with which to add files to staging.
            auto_lfs_track (`bool`, *optional*, defaults to `False`):
                Whether to automatically track large and binary files with
                git-lfs. Any file over 10MB in size, or in binary format, will
                be automatically tracked.
        z!Adding files tracked by Git LFS: z5. This may take a bit of time if the files are large.z
git add -vzAdding to index:
r`   N)r  Úextendr  rº   rô   r   rN   rÉ   ré   r6   rB   re   rŠ   r4   )r(   r‰   r  Ztracked_filesr.   rm   r)   r)   r*   Úgit_addé  s    

ÿzRepository.git_addúcommit files to HF hub)Úcommit_messagec              
   C   s|   z.t d ¡ |g | jƒ}t d|j› d�¡ W nH tjk
rv } z(t|j	ƒdkr\t
|j	ƒ‚n
t
|jƒ‚W 5 d}~X Y nX dS )z·
        git commit

        Args:
            commit_message (`str`, *optional*, defaults to "commit files to HF hub"):
                The message attributed to the commit.
        zgit commit -v -mzCommitted:
r`   r   N)r   rN   rÉ   rº   ré   r6   rB   re   rg   r4   rŠ   )r(   r  r.   rm   r)   r)   r*   Ú
git_commit  s    zRepository.git_commit)r�   ÚblockingÚauto_lfs_pruner-   c              
      s^  d}|r|d|› �7 }t | j|ƒ}|dkrJt d|› d�¡ |rJt d¡ z~tƒ �n tj| ¡ tjtjd| jd�‰ |r¼ˆ  	¡ \}}ˆ  
¡ }ˆ  ¡  t|ƒr¤t |¡ |r¼tj|ˆ j||d	�‚W 5 Q R X W n. tjk
rö }	 zt|	jƒ‚W 5 d
}	~	X Y nX |�sH‡ fdd„}
td‡ fdd„|
ˆ |�r(| jnd
d�}| j |¡ |  ¡ |fS |�rV|  ¡  |  ¡ S )a%  
        git push

        If used without setting `blocking`, will return url to commit on remote
        repo. If used with `blocking=True`, will return a tuple containing the
        url to commit and the command object to follow for information about the
        process.

        Args:
            upstream (`str`, *optional*):
                Upstream to which this should push. If not specified, will push
                to the lastly defined upstream or to the default one (`origin
                main`).
            blocking (`bool`, *optional*, defaults to `True`):
                Whether the function should return only when the push has
                finished. Setting this to `False` will return an
                `CommandInProgress` object which has an `is_done` property. This
                property will be set to `True` when the push is finished.
            auto_lfs_prune (`bool`, *optional*, defaults to `False`):
                Whether to automatically prune files once they have been pushed
                to the remote.
        zgit pushz --set-upstream r   zSeveral commits (z) will be pushed upstream.z$The progress bars may be unreliable.zutf-8)r4   r6   ÚencodingrH   )rø   r4   Nc                     s   ˆ   ¡ } | d krdS | S d S )Nr7   ©Úpollr2   ©r   r)   r*   r   ^  s    z*Repository.git_push.<locals>.status_methodÚpushc                      s   ˆ   ¡ d k	S ©Nr  r)   r!  r)   r*   Ú<lambda>g  ó    z%Repository.git_push.<locals>.<lambda>)r   r   r   r    )r�   rÉ   rº   rô   rÄ   rB   rC   rN   rO   Úcommunicater   Úkillrg   re   r¸   rŠ   r4   r   r  rÆ   r  rþ   )r(   r�   r  r  r  Znumber_of_commitsr6   r4   Zreturn_coderm   r   Zcommand_in_progressr)   r!  r*   Úgit_push  sR    
û
"
ûzRepository.git_push)rÏ   r×   c                 C   sà   z<t d|› �| jƒ}t d|› d| j› d�¡ t |j¡ W nž tjk
rÚ } z~|s`t|j	ƒ‚njz:t d|› �| jƒ}t d|› d|› d�¡ t |j¡ W n. tjk
rÈ } zt|j	ƒ‚W 5 d	}~X Y nX W 5 d	}~X Y nX d	S )
a  
        git checkout a given revision

        Specifying `create_branch_ok` to `True` will create the branch to the
        given revision if that revision doesn't exist.

        Args:
            revision (`str`):
                The revision to checkout.
            create_branch_ok (`str`, *optional*, defaults to `False`):
                Whether creating a branch named with the `revision` passed at
                the current checked-out reference if `revision` isn't an
                existing revision is allowed.
        zgit checkout zChecked out z from rˆ   zgit checkout -b z
Revision `z2` does not exist. Created and checked out branch `z`.N)
r   rÉ   rº   rô   rç   r6   rB   re   rŠ   r4   )r(   rÏ   r×   r.   rm   r)   r)   r*   rá   v  s    ÿzRepository.git_checkout)Útag_namerX   r-   c              
   C   s¸   |r\zt d|› �| jƒj ¡ }W n. tjk
rN } zt|jƒ‚W 5 d}~X Y nX t|ƒdkS zt d| jƒj ¡ }W n. tjk
r  } zt|jƒ‚W 5 d}~X Y nX | 	d¡}||kS dS )aw  
        Check if a tag exists or not.

        Args:
            tag_name (`str`):
                The name of the tag to check.
            remote (`str`, *optional*):
                Whether to check if the tag exists on a remote. This parameter
                should be the identifier of the remote.

        Returns:
            `bool`: Whether the tag exists.
        zgit ls-remote origin refs/tags/Nr   zgit tagr`   r  )r(   r)  rX   r.   rm   Zgit_tagsr)   r)   r*   Ú
tag_exists–  s    
zRepository.tag_existsc              
   C   sØ   d}d}|   |¡sd}| j ||d�s(d}|rzztddd|g| jƒj ¡  W n. tjk
rx } zt|jƒ‚W 5 d}~X Y nX |rÔ|rÔz"td|› d	|› �| jƒj ¡  W n. tjk
rÒ } zt|jƒ‚W 5 d}~X Y nX dS )
a˜  
        Delete a tag, both local and remote, if it exists

        Args:
            tag_name (`str`):
                The tag name to delete.
            remote (`str`, *optional*):
                The remote on which to delete the tag.

        Returns:
             `bool`: `True` if deleted, `False` if the tag didn't exist.
                If remote is not passed, will just be updated locally
        TF)rX   Úgitro   z-dNú	git push z
 --delete )	r*  r   rÉ   r6   rd   rB   re   rŠ   r4   )r(   r)  rX   Zdelete_locallyZdelete_remotelyrm   r)   r)   r*   Ú
delete_tag´  s"    
"zRepository.delete_tag)r)  rÈ   rX   c              
   C   sÀ   |rddd|d|g}n
dd|g}zt || jƒj ¡  W n. tjk
rd } zt|jƒ‚W 5 d}~X Y nX |r¼z"t d|› d|› �| jƒj ¡  W n. tjk
rº } zt|jƒ‚W 5 d}~X Y nX dS )a[  
        Add a tag at the current head and push it

        If remote is None, will just be updated locally

        If no message is provided, the tag will be lightweight. if a message is
        provided, the tag will be annotated.

        Args:
            tag_name (`str`):
                The name of the tag to be added.
            message (`str`, *optional*):
                The message that accompanies the tag. The tag will turn into an
                annotated tag if a message is passed.
            remote (`str`, *optional*):
                The remote on which to add the tag.
        r+  ro   z-az-mNr,  rî   ræ   )r(   r)  rÈ   rX   Ztag_argsrm   r)   r)   r*   Úadd_tagÙ  s    
"zRepository.add_tagc              
   C   sR   zt d| jƒj ¡ }W n. tjk
rD } zt|jƒ‚W 5 d}~X Y nX t|ƒdkS )z¢
        Return whether or not the git status is clean or not

        Returns:
            `bool`: `True` if the git status is clean, `False` otherwise.
        zgit status --porcelainNr   )	r   rÉ   r6   rd   rB   re   rŠ   r4   rg   )r(   r  rm   r)   r)   r*   Úis_repo_cleanû  s
    zRepository.is_repo_clean)r  r  Úclean_okr  r-   c                 C   sH   |r|   ¡ rt d¡ dS | jdd� |  |¡ | jd| j› �||d�S )aF  
        Helper to add, commit, and push files to remote repository on the
        HuggingFace Hub. Will automatically track large files (>10MB).

        Args:
            commit_message (`str`):
                Message to use for the commit.
            blocking (`bool`, *optional*, defaults to `True`):
                Whether the function should return only when the `git push` has
                finished.
            clean_ok (`bool`, *optional*, defaults to `True`):
                If True, this function will return None if the repo is
                untouched. Default behavior is to fail because the git command
                fails.
            auto_lfs_prune (`bool`, *optional*, defaults to `False`):
                Whether to automatically prune files once they have been pushed
                to the remote.
        z*Repo currently clean. Ignoring push_to_hubNT©r  úorigin ©r�   r  r  )r/  rº   ré   r  r  r(  rç   )r(   r  r  r0  r  r)   r)   r*   Úpush_to_hub	  s    


ýzRepository.push_to_hub)r  ÚbranchÚtrack_large_filesr  r  c           
      c   s�  t d| jd�}t|ƒrXt|ƒdkr>t|dd… ƒdd… d nt|ƒ}t d|› d�¡ |dk	rn| j|d	d
� t| jƒr�t d¡ | j	d	d� nt d| j
› d�¡ t ¡ }t tj || j¡¡ z
| V  W 5 | j|d� z|  |¡ W n6 tk
�r }	 zdt|	ƒk�r|	‚W 5 d}	~	X Y nX z| jd| j
› �||d� W nB tk
�r~ }	 z"dt|	ƒk�rjtdƒ|	‚n|	‚W 5 d}	~	X Y nX t |¡ X dS )a…  
        Context manager utility to handle committing to a repository. This
        automatically tracks large files (>10Mb) with git-lfs. Set the
        `track_large_files` argument to `False` if you wish to ignore that
        behavior.

        Args:
            commit_message (`str`):
                Message to use for the commit.
            branch (`str`, *optional*):
                The branch on which the commit will appear. This branch will be
                checked-out before any operation.
            track_large_files (`bool`, *optional*, defaults to `True`):
                Whether to automatically track large files or not. Will do so by
                default.
            blocking (`bool`, *optional*, defaults to `True`):
                Whether the function should return only when the `git push` has
                finished.
            auto_lfs_prune (`bool`, defaults to `True`):
                Whether to automatically prune files once they have been pushed
                to the remote.

        Examples:

        ```python
        >>> with Repository(
        ...     "text-files",
        ...     clone_from="<user>/text-files",
        ...     token=True,
        >>> ).commit("My first file :)"):
        ...     with open("file.txt", "w+") as f:
        ...         f.write(json.dumps({"hey": 8}))

        >>> import torch

        >>> model = torch.nn.Transformer()
        >>> with Repository(
        ...     "torch-model",
        ...     clone_from="<user>/torch-model",
        ...     token=True,
        >>> ).commit("My cool model :)"):
        ...     torch.save(model.state_dict(), "model.pt")
        ```

        rˆ   r  é   Nr7   z, ...]zPThere exists some updated files in the local repository that are not committed: z|. This may lead to errors if checking out a branch. These files and their modifications will be added to the current commit.TrÖ   zPulling changes ...)r  z@The current branch has no upstream branch. Will push to 'origin ú'r1  znothing to commitr2  r3  zcould not read UsernamezCCouldn't authenticate user for push. Did you set `token` to `True`?)rŒ   rÉ   rg   rA   rº   r³   rá   rŽ   rô   r  rç   rI   rÚ   ÚchdirrJ   rL   r  r  rf   r(  )
r(   r  r5  r6  r  r  Zfiles_to_stageZfiles_in_msgZcurrent_working_directoryÚer)   r)   r*   Úcommit-  sB    70
ÿ



ý
zRepository.commitc                 C   s*   t j | jtj¡}t j |¡r&t|ƒS d S r#  )rI   rJ   rL   rÉ   r   ÚREPOCARD_NAMEÚisfiler   )r(   Úfilepathr)   r)   r*   Úrepocard_metadata_load–  s    z!Repository.repocard_metadata_load)Údatar-   c                 C   s   t tj | jtj¡|ƒS r#  )r   rI   rJ   rL   rÉ   r   r<  )r(   r@  r)   r)   r*   Úrepocard_metadata_saveœ  s    z!Repository.repocard_metadata_savec                 C   s   dd„ | j D ƒS )z@
        Returns the asynchronous commands that failed.
        c                 S   s   g | ]}|j d kr|‘qS )r   r2   ©rW   Úcr)   r)   r*   rY   ¤  s     
 z.Repository.commands_failed.<locals>.<listcomp>©rÆ   r0   r)   r)   r*   Úcommands_failedŸ  s    zRepository.commands_failedc                 C   s   dd„ | j D ƒS )zS
        Returns the asynchronous commands that are currently in progress.
        c                 S   s   g | ]}|j s|‘qS r)   )r/   rB  r)   r)   r*   rY   «  s      z3Repository.commands_in_progress.<locals>.<listcomp>rD  r0   r)   r)   r*   Úcommands_in_progress¦  s    zRepository.commands_in_progressc                 C   sx   d}| j D ].}t d|j› d|jj› d�¡ t |j¡ q
| jrt|d dkr`t d| j› d�¡ |d7 }t	 
d¡ q:d	S )
zr
        Blocking method: blocks all subsequent execution until all commands have
        been processed.
        r   zThe z command with PID z failed.rx   zCWaiting for the following commands to finish before shutting down: rˆ   r   N)rE  rº   r³   r   r$   r;   r4   rF  rô   r¡   r¢   )r(   ÚindexZcommand_failedr)   r)   r*   rä   ­  s    
ÿzRepository.wait_for_commands)NNTNNNFN)N)NN)F)rˆ   )rˆ   )F)FF)rˆ   F)r  )NTF)F)N)N)NN)r  TTF)NTTF)3r=   r>   r?   r@   r   r   r”   r   r   r   rA   r   r   rE   r   r+   rD   rç   rÜ   rÊ   rÞ   rà   rú   rü   rþ   r  r  r  rß   r  r  r  r  r  r  r	   r(  rá   r*  r-  r.  r/  r4  r   r;  r   r?  rA  rE  rF  rä   r)   r)   r)   r*   rÅ   ª  s´   
ý        ö

öl|	#+!
"   üûZ %"    ûú$    úúh

rÅ   )rˆ   N)N):râ   rI   rU   rB   r¾   r¡   Ú
contextlibr   Úpathlibr   Útypingr   r   r   r   r   r	   r
   r   Úurllib.parser   Zhuggingface_hubr   Zhuggingface_hub.repocardr   r   Zhf_apir   r   ra   r   Úutilsr   r   r   r   r   r   Zutils._deprecationr   Z
get_loggerr=   rº   r   rA   rE   rQ   r[   rp   rs   r‡   rŒ   rŽ   rF   r�   r‘   rÄ   rÅ   r)   r)   r)   r*   Ú<module>   s:   ( 
S%" 
m