a
    h                     @   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)   V/var/www/html/assistant/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 )
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 }||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 )rS   rT   )resub).0remoter)   r)   r*   
<listcomp>       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 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   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"    

 rq   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   rc   rd   r   rN   rE   rP   rB   rf   rg   r4   )r]   rG   rl   Z
is_ignoredrn   r)   r)   r*   is_git_ignored   s    

 rt   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rangerE   	translateUnicodeDecodeError)r]   fcontentZ
text_charsr)   r)   r*   is_binary_file   s    ( r   .)patternrG   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 -mora   N)	r   rN   rh   r6   re   rB   rf   EnvironmentErrorr4   )r   rG   rl   filesrn   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   rB   rf   r4   rg   )rG   rn   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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!   ra   r   N)r   rh   r6   rN   rB   rf   r   r4   )rG   r   r.   rn   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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                    sJ  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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   )rk   updatetotal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   ra   r   )r   is_setreadlinerh   re   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_divisorrd   )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
RepositoryaR  
    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.

    <Tip warning={true}>

    [`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.

    </Tip>
    command_queuez1.0zPlease 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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r2| || |   |   |du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   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   re   rB   rf   r   r4   )r(   r.   rn   r)   r)   r*   current_branch3  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).ra   N)r   r   r6   re   FileNotFoundErrorr   r   info)r(   Zgit_versionZlfs_versionr)   r)   r*   r   B  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jv r|tj| 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rh|
ddi t| jrvdnd d| d| j|
d W d   n1 s0    Y  nt| jstd| j d| j dt| j|r t| j d|	 d nTtd| jdd}d |	 d!|	 d"}|j dkrLt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 originrr   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endpointrh   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   rf   r4   )r(   r   r   r   r   	namespace	repo_nameZrepo_idr   Zclean_repo_urlr   output	error_msgZclean_local_remote_urlrn   r)   r)   r*   r   Y  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   rN   r   rB   rf   r   r4   )r(   r   r   rn   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   rB   rf   r   r4   )r(   rn   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(   rl   rn   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.urlrS   rT   N)
r   r   r6   re   rU   rV   rB   rf   r   r4   )r(   rl   urlrn   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)   )re   rW   r1   r)   r)   r*   rY   8  rZ   z1Repository.list_deleted_files.<locals>.<listcomp>ra   c                 S   s    g | ]}d |  d v r|qS )Dr   )rN   r   r)   r)   r*   rY   ;  rZ   c                 S   s   g | ]}|  d   qS )r7   )rN   re   r   r)   r)   r*   rY   >  rZ   
r   r   r6   re   rB   rf   r   r4   rh   rN   )r(   
git_statusrn   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   rA   r   r   rB   rf   r   r4   )r(   r  r]   r   rn   r)   r)   r*   	lfs_trackB  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   rA   r   rN   r   rB   rf   r   r4   )r(   r  r   rn   r)   r)   r*   lfs_untrack[  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 hfz.args N)r   r   r   rB   rf   r   r4   )r(   Z
lfs_configrn   r)   r)   r*   r   k  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
        rG      ry   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   rI   rJ   rL   r   rq   rt   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_filesy  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
  ry   )r  r   r   rI   rJ   rL   r   r  rq   rt   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   rB   rf   r   r4   )r(   Zrecentr.   rn   r)   r)   r*   	lfs_prune  s    .zRepository.lfs_prune)rebaserb   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  rb   commandr.   rn   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:
ra   N)r  extendr  r   r   r   rN   r   r   r6   rB   rf   r   r4   )r(   r   r  Ztracked_filesr.   rn   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:
ra   r   N)r   rN   r   r   r   r6   rB   rf   rh   r4   r   )r(   r  r.   rn   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   encodingrH   )r   r4   Nc                     s      } | d u rdS | S d S )Nr7   pollr2   r   r)   r*   r   d  s    z*Repository.git_push.<locals>.status_methodpushc                      s      d uS Nr   r)   r"  r)   r*   <lambda>m  rZ   z%Repository.git_push.<locals>.<lambda>)r   r   r   r    )r   r   r   r   r   rB   rC   rN   rO   communicater!  killrh   rf   r   r   r4   r   r  r   r  r   )r(   r   r  r  r  Znumber_of_commitsr6   r4   Zreturn_codern   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   rB   rf   r   r4   )r(   r   r   r.   rn   r)   r)   r*   r   |  s    zRepository.git_checkout)tag_namerX   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 tagra   r  )r(   r)  rX   r.   rn   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)rX   gitrp   z-dN	git push z
 --delete )	r*  r   r   r6   re   rB   rf   r   r4   )r(   r)  rX   Zdelete_locallyZdelete_remotelyrn   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 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+  rp   z-az-mNr,  r   r   )r(   r)  r   rX   Ztag_argsrn   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   re   rB   rf   r   r4   rh   )r(   r  rn   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   sT  t d| jd}t|rXt|dkr>t|dd dd d nt|}td| d |durn| 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y }	 z*dt|	v rht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yB }	 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 'r1  znothing to commitr2  r3  zcould not read UsernamezCCouldn't authenticate user for push. Did you set `token` to `True`?)r   r   rh   rA   r   r   r   r   r   r  r   rI   r   chdirrJ   rL   r  r  rg   r(  )
r(   r  r5  r6  r  r  Zfiles_to_stageZfiles_in_msgZcurrent_working_directoryer)   r)   r*   commit3  sh    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     rZ   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     rZ   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.ry   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   rb   r   utilsr   r   r   r   r   r   Zutils._deprecationr   Z
get_loggerr=   r   r   rA   rE   rQ   r\   rq   rt   r   r   r   rF   r   r   r   r   r)   r)   r)   r*   <module>   s:   ( 
S%" 
m