U
    9%e                     @   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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& 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Z/ee+e	f e,dddZ0ee+e	f e,dddZ1d*e+ee+e	df ee+ dddZ2ee+e	f e,ddd Z3d+ee+e	f ee+ e4d!d"d#Z5G d$d% d%eZ6ed&d' Z7G d(d) d)Z8dS ),    N)contextmanager)Path)CallableDictIteratorListOptionalTuple	TypedDict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_argsc                   @   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/Darija-Ai-API/env/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_done3   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*   status@   s    	zCommandInProgress.statusc                 C   s
   | j dkS )z2
        Whether the process errored-out.
        r   r1   r0   r)   r)   r*   failedK   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   R   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__d   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_repoq   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rdS dddd}|dD ]*}| D ]}||krd|k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 -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   5  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                    sF  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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_pbarsQ  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_fileW  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   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_progressI  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&    
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k	rR|	nt | _|   t |trt|| _n|dkrd| _n
t | _|dk	r| j|d nt| jrt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	r0| || |   |   |dk	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   rA   rI   makedirsrJ   rL   getcwdr   
_repo_typer   r   r   r   check_git_versionshuggingface_tokenr   	get_tokenr   rQ   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   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_branch   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 --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   /  s    
zRepository.check_git_versions)r   r   c              
   C   sr  t |tr|n|dkrdn| j}|dk	r:|dr:td| jj}||ksdd|krt|ddkrt	||d\}}}|dk	r| d| n|}|dk	r|| _
|d }| j
tkr|t| j
 7 }|dk	rt|j}|| d	| d
| d}||7 }tdd|}	z6td| j tt| jdkrtd|	 d t N tj }
| jrd|
ddi t| jrrdnd d| d| j|
d W 5 Q R X 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r2td#d$|j }|d%| 7 }t|W n0 t!j"k
rl } 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.

        </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   rS   rT   z'
Local path has its origin defined as: )$r   rA   r   
startswithr   r   Zendpointrg   rN   r   r   r   r   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   F  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   %  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   (  s      c                 S   s   g | ]}|  d   qS )r7   )rN   rd   r   r)   r)   r*   rY   +  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_untrackH  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 huggingface-cliz.args N)r   r   r   rB   re   r   r4   )r(   Z
lfs_configrm   r)   r)   r*   r   X  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   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   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_filesf  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|rt| |rt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   Q  s    z*Repository.git_push.<locals>.status_methodpushc                      s      d k	S Nr  r)   r   r)   r*   <lambda>Z      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   i  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|rz"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(  messagerX   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 |rz"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|rPt|dkr>t|dd dd d }td| d |dk	rf| j|d	d
 t| jrt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
rv }	 z"dt|	krbt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   sD    7





zRepository.commitc                 C   s(   t j| jt}t j|r$t|S d S r"  )rI   rJ   rL   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   rI   rJ   rL   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/   rA  r)   r)   r*   rY     s      z3Repository.commands_in_progress.<locals>.<listcomp>rC  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)rD  r   r   r   r$   r;   r4   rE  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   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>  r@  rD  rE  r   r)   r)   r)   r*   r     s   
        

l	#+!
"   Z %"    $    j

r   )r   N)N)9r   rI   rU   rB   r   r   
contextlibr   pathlibr   typingr   r   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
get_loggerr=   r   r   rA   rE   rQ   r[   rp   rs   r   r   r   rF   r   r   r   r   r)   r)   r)   r*   <module>   s8   ( 

S%" 
l