a
    
d                     @   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 d dlmZ d dlmZ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Union)urlparse)REPO_TYPES_URL_PREFIXESREPOCARD_NAME)metadata_loadmetadata_save   )HfApirepo_type_and_id_from_hf_id)LFS_MULTIPART_UPLOAD_COMMAND)HfFolderSoftTemporaryDirectoryloggingrun_subprocesstqdmvalidate_hf_hub_args)	TypedDictc                   @   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)   c/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/huggingface_hub/repository.py__init__$   s    zCommandInProgress.__init__returnc                 C   s(   |   }|r$| jdu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u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u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 )
NZ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joinrA   runsplitPIPE
returncode)rF   Zfolder_existsZ
git_branchr)   r)   r*   is_git_repor   s    rP   )rF   
remote_urlr-   c                 C   s@   t | sdS td| j}tdd|}dd | D }||v 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 )rR   rS   )resub).0remoter)   r)   r*   
<listcomp>       z"is_local_clone.<locals>.<listcomp>)rP   r   r6   rT   rU   rM   )rF   rQ   remotesr)   r)   r*   is_local_clone   s    r[   )filenamer-   c              
   C   s   t | j}t | j} z"td | g |}|j }W nF tjy| } z,t	|s^W Y d}~dS t
|jW Y d}~n
d}~0 0 t|dkrdS dddd}|dD ]*}| D ]}||v rd|v rd||< qqt| 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 -aNFr   )diffmergefilter
lfsT)r   parentnamer   rM   r6   striprA   CalledProcessErrorrP   OSErrorr4   lenkeysallvalues)r\   rF   p
attributesexcZfound_lfs_tag	attributetagr)   r)   r*   is_tracked_with_lfs   s"    

 rp   c              
   C   sr   t | j}t | j} z(td | g |dd}t|j }W n0 tjyl } zt	|j
W Y d}~n
d}~0 0 |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   rM   rD   rO   rA   re   rf   r4   )r\   rF   rk   Z
is_ignoredrm   r)   r)   r*   is_git_ignored   s    

 rs   c                 C   s   zft | d}|d}W d   n1 s,0    Y  th dttdddh B }t|d|W S  tyz   Y dS 0 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   N>         	   
                      T)openr5   	bytearraysetrangerD   	translateUnicodeDecodeError)r\   fcontentZ
text_charsr)   r)   r*   is_binary_file   s    ( r   .)patternrF   r-   c              
   C   sr   z<t d | g |}t|j r6|j d}ng }W n0 tjyl } zt|jW Y d}~n
d}~0 0 |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   rM   rg   r6   rd   rA   re   EnvironmentErrorr4   )r   rF   rk   filesrm   r)   r)   r*   files_to_be_staged   s     r   c              
   C   sP   zt d|  W dS  tjyJ } z d|jv r4tdW Y d}~dS d}~0 0 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 outNF)r   rA   re   r4   rf   )rF   rm   r)   r)   r*   is_tracked_upstream
  s    

r   )rF   upstreamr-   c              
   C   s`   z*t d|pd | }t|jdd W S  tjyZ } zt|jW Y d}~n
d}~0 0 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   rM   rA   re   r   r4   )rF   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__rE   r)   r)   r)   r*   r   6  s   
r   c               
   c   s  t  tjkr0z
dV  W n ty*   Y n0 dS tjddd} tj	dd}t
 }tj|dtjd< t dtjd   t }tj| |fd	d
}|  z$dV  W |  |  |tjd< n|  |  |tjd< 0 W d   n1 s0    Y  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 n4 t
y } zt
d	| |W Y d}~n
d}~0 0 |  d
| }|	d\}	}
t|	}t|
}||f}|du r$t|||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totalZrefreshclose)pbar)pbarsr)   r*   close_pbarsR  s    z?_lfs_log_progress.<locals>.output_progress.<locals>.close_pbarsr,   c                 3   s   t | dn}d} r    qj| }|dur^t| dks^||7 }|drh|V  d}qtd qW d   n1 s~0    Y  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   )descinitialr   unitZ
unit_scaleZunit_divisor)r   r   r   r   )r   r@   rH   rI   rJ   environr   r   r   rM   
ValueError
capitalizerE   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EventrH   r   r   r   rI   rK   debugThreadstartr   )r   Zcurrent_lfs_progress_valuetmpdirZ
exit_eventxr)   r)   r*   _lfs_log_progress<  s,    
Lr   c                   @   s  e Zd ZU dZee ed< edYe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dZe	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d^e	ee	 d'd*d+Zd_d,d-Zd`eed.d/d0Zdae	ed1d2d3Z dbe	d5d6d7Z!dcee	 eeee	e"e	ef f d8d9d:Z#dde	ed;d<d=Z$dee	ee	 ed>d?d@Z%dfe	ee	 ed>dAdBZ&dge	ee	 ee	 dCdDdEZ'ed	dFdGZ(dhe	eeeede	e"e	ef f dHdIdJZ)e*die	ee	 eeedKdLdMZ+ee, d	dNdOZ-e,ddPdQdRZ.edSdT Z/edUdV Z0dWdX Z1dS )j
Repositoryz
    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.
    command_queueNTF)		local_dir
clone_from	repo_typetokengit_user	git_emailrevisionskip_lfs_filesclientc
                 C   sh  t |trt|}tj|dd tjt || _|| _	g | _
|| _|	durR|	nt | _|   t |trt|| _n|du rd| _n
t | _|dur| j|d nt| jrtd ntd| jdur|du s|du r| j| j}
|du r|
d }|du r|
d	 }|dus$|dur0| || |   |   |durX| 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 `huggingface-cli 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   r@   rH   makedirsrI   rK   getcwdr   
_repo_typer   r   r   r   check_git_versionshuggingface_tokenr   	get_tokenr   rP   r   r   r   Zwhoami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@    ;





zRepository.__init__r,   c              
   C   sL   zt d| jj }W n0 tjyF } zt|jW Y d}~n
d}~0 0 |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   rA   re   r   r4   )r(   r.   rm   r)   r)   r*   current_branch!  s
     zRepository.current_branchc                 C   sz   zt d| jj }W n ty0   tdY n0 zt d| jj }W n tyb   tdY n0 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 --versionzLooks 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   0  s    
zRepository.check_git_versions)r   r   c              
   C   s  t |tr|n|du rdn| j}|dur:|dr:td| jj}||v sdd|vrt|ddkrt	||d\}}}|dur| d| n|}|dur|| _
|d }| j
tv r|t| j
 7 }|durt|j}|| d	| d
| d}||7 }tdd|}	zLtd| j tt| jdkrtd|	 d t X tj }
| jrd|
ddi t| jrrdnd d| d| j|
d W d   n1 s0    Y  nt| jstd| j d| j dt| j|rt| j d|	 d nTtd| jdd}d |	 d!|	 d"}|jdkrHtd#d$|j }|d%| 7 }t|W n2 t!j"y } zt|j#W Y d}~n
d}~0 0 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.

        </Tip>
        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   rR   rS   z'
Local path has its origin defined as: )$r   r@   r   
startswithr   r   Zendpointrg   rM   r   r   r   r   schemereplacerT   rU   r   r   rH   listdirr   warningr   r   copyr   r   rP   r   r[   rO   r6   rA   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   G  sx    &	"


(
	zRepository.clone_from)r   r   c              
   C   sv   z@|dur t d |g | j |dur>t d|  | j W n0 tjyp } zt|jW Y d}~n
d}~0 0 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   rM   r   rA   re   r   r4   )r(   r   r   rm   r)   r)   r*   r     s    
z(Repository.git_config_username_and_emailc              
   C   sF   zt d| j W n0 tjy@ } zt|jW Y d}~n
d}~0 0 dS )z;
        Sets the git credential helper to `store`
        z"git config credential.helper storeN)r   r   rA   re   r   r4   )r(   rm   r)   r)   r*   r     s    z&Repository.git_credential_helper_storec              
   C   sN   zt d| j}|j W S  tjyH } zt|jW Y d}~n
d}~0 0 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   s\   z&t d| j}|j }tdd|W S  tjyV } zt|j	W Y d}~n
d}~0 0 dS )zp
        Get URL to origin remote.

        Returns:
            `str`: The URL of the `origin` remote.
        z"git config --get remote.origin.urlrR   rS   N)
r   r   r6   rd   rT   rU   rA   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 n0 tjyF } zt|jW Y d}~n
d}~0 0 t|dkrXg 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   rV   r1   r)   r)   r*   rX   &  rY   z1Repository.list_deleted_files.<locals>.<listcomp>r`   c                 S   s    g | ]}d |  d v r|qS )Dr   )rM   r   r)   r)   r*   rX   )  rY   c                 S   s   g | ]}|  d   qS )r7   )rM   rd   r   r)   r)   r*   rX   ,  rY   
r   r   r6   rd   rA   re   r   r4   rg   rM   )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   st   t |tr|g}z.|D ]$}td|r&dnd d| | j qW n0 tjyn } zt|jW Y d}~n
d}~0 0 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   r@   r   r   rA   re   r   r4   )r(   r  r\   r   rm   r)   r)   r*   	lfs_track0  s    

zRepository.lfs_track)r  c              
   C   sj   t |tr|g}z$|D ]}td |g | j qW n0 tjyd } zt|jW Y d}~n
d}~0 0 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   r@   r   rM   r   rA   re   r   r4   )r(   r  r   rm   r)   r)   r*   lfs_untrackI  s    
zRepository.lfs_untrackc              
   C   sf   z0d}t | d| j t | dt | j W n0 tjy` } zt|jW Y d}~n
d}~0 0 dS )zI
        HF-specific. This enables upload support of files >5GB.
        z'git config lfs.customtransfer.multipartz.path huggingface-cliz.args N)r   r   r   rA   re   r   r4   )r(   Z
lfs_configrm   r)   r)   r*   r   Y  s    z Repository.lfs_enable_largefilesr   )r   r-   c                 C   s   g }|   }t|| jdD ]v}||v 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
        rF      rx   zParsing 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   rH   rI   rK   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_filesg  s$    

z"Repository.auto_track_binary_filesc                 C   s   g }|   }t|| jdD ]`}||v 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   rH   rI   rK   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   s   zPt  6 td|rdnd | j}t|j W d   n1 sD0    Y  W n0 tjy } zt|j	W Y d}~n
d}~0 0 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   rA   re   r   r4   )r(   Zrecentr.   rm   r)   r)   r*   	lfs_prune  s    .zRepository.lfs_prune)rebasera   c              
   C   s   |sdnd}|r|d7 }zBt  ( t|| j}t|j W d   n1 sN0    Y  W n0 tjy } zt|j	W Y d}~n
d}~0 0 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 n0 t
jy } zt|jW Y d}~n
d}~0 0 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   rM   r   r   r6   rA   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 nJ tjyx } z0t|j	dkrZt
|j	n
t
|jW Y d}~n
d}~0 0 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   rM   r   r   r   r6   rA   re   rg   r4   r   )r(   r  r.   rm   r)   r)   r*   
git_commit  s    zRepository.git_commit)r   blockingauto_lfs_pruner-   c              
      sv  d}|r|d| 7 }t | j|}|dkrJtd| d |rJtd zt x tj| tjtjd| jd |r 	 \}} 
 }   t|rt| |rtj| j||d	W d
   n1 s0    Y  W n2 tjy }	 zt|	jW Y d
}	~	n
d
}	~	0 0 |s` fdd}
td fdd|
 |r@| jnd
d}| j| |  |fS |rn|   |  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   encodingrG   )r   r4   Nc                     s      } | d u rdS | S d S )Nr7   pollr2   r   r)   r*   r   R  s    z*Repository.git_push.<locals>.status_methodpushc                      s      d uS Nr  r)   r   r)   r*   <lambda>[  rY   z%Repository.git_push.<locals>.<lambda>)r   r   r   r    )r   r   r   r   r   rA   rB   rM   rN   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    

6 
zRepository.git_push)r   r   c                 C   s   z<t d| | j}td| d| j d t|j W n tjy } z|s^t|j	nlz:t d| | j}td| d| d t|j W n0 tjy } zt|j	W Y d	}~n
d	}~0 0 W Y d	}~n
d	}~0 0 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   rA   re   r   r4   )r(   r   r   r.   rm   r)   r)   r*   r   j  s    zRepository.git_checkout)tag_namerW   r-   c              
   C   s   |r^zt d| | jj }W n0 tjyP } zt|jW Y d}~n
d}~0 0 t|dkS zt d| jj }W n0 tjy } zt|jW Y d}~n
d}~0 0 |	d}||v 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'  rW   r.   rm   Zgit_tagsr)   r)   r*   
tag_exists  s      
zRepository.tag_existsc              
   C   s   d}d}|  |sd}| j ||ds(d}|r|ztddd|g| jj  W n0 tjyz } zt|jW Y d}~n
d}~0 0 |r|rz"td| d	| | jj  W n0 tjy } zt|jW Y d}~n
d}~0 0 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)rW   gitro   z-dN	git push z
 --delete )	r(  r   r   r6   rd   rA   re   r   r4   )r(   r'  rW   Zdelete_locallyZdelete_remotelyrm   r)   r)   r*   
delete_tag  s"    
 " zRepository.delete_tag)r'  messagerW   c              
   C   s   |rddd|d|g}n
dd|g}zt || jj  W n0 tjyf } zt|jW Y d}~n
d}~0 0 |rz"t d| d| | jj  W n0 tjy } zt|jW Y d}~n
d}~0 0 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,  rW   Ztag_argsrm   r)   r)   r*   add_tag  s    
 "zRepository.add_tagc              
   C   sT   zt d| jj }W n0 tjyF } zt|jW Y d}~n
d}~0 0 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   rA   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  r/  r  r)   r)   r*   push_to_hub  s    


zRepository.push_to_hub)r  branchtrack_large_filesr  r  c           
      c   sL  t d| jd}t|rPt|dkr>t|dd dd d }td| d |durf| j|d	d
 t| jrtd | j	d	d ntd| j
 d t }ttj|| j z| V  W | j|d z| | W n8 ty }	 zdt|	vr|	W Y d}	~	n
d}	~	0 0 z| jd| j
 ||d W nD tyx }	 z*dt|	v r`td|	n|	W Y d}	~	n
d}	~	0 0 t| n| j|d z| | W n8 ty }	 zdt|	vr|	W Y d}	~	n
d}	~	0 0 z| jd| j
 ||d W nD ty: }	 z*dt|	v r"td|	n|	W Y d}	~	n
d}	~	0 0 t| 0 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 'r0  znothing to commitr1  r2  zcould not read UsernamezCCouldn't authenticate user for push. Did you set `token` to `True`?)r   r   rg   r@   r   r   r   r   r   r  r   rH   r   chdirrI   rK   r  r  rf   r&  )
r(   r  r4  r5  r  r  Zfiles_to_stageZfiles_in_msgZcurrent_working_directoryer)   r)   r*   commit!  sj    7





zRepository.commitc                 C   s(   t j| jt}t j|r$t|S d S r"  )rH   rI   rK   r   r   isfiler   )r(   filepathr)   r)   r*   repocard_metadata_load  s    z!Repository.repocard_metadata_load)datar-   c                 C   s   t tj| jt|S r"  )r   rH   rI   rK   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   rV   cr)   r)   r*   rX     rY   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/   r@  r)   r)   r*   rX     rY   z3Repository.commands_in_progress.<locals>.<listcomp>rB  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)rC  r   r   r   r$   r:   r4   rD  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)2r<   r=   r>   r?   r   r   r   r   r
   r@   r   r   rD   r   r+   rC   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.  r3  r   r:  r   r=  r?  rC  rD  r   r)   r)   r)   r*   r     s   
        

l	#+!
"   Z %"    $    j

r   )r   N)N):r   rH   rT   rA   r   r   
contextlibr   pathlibr   typingr   r   r   r   r   r	   r
   urllib.parser   Zhuggingface_hub.constantsr   r   Zhuggingface_hub.repocardr   r   Zhf_apir   r   ra   r   utilsr   r   r   r   r   r   Zutils._typingr   Z
get_loggerr<   r   r   r@   rD   rP   r[   rp   rs   r   r   r   rE   r   r   r   r   r)   r)   r)   r*   <module>   s:   $ 
S%" 
l