o
    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+dee,e	f de-fddZ.dee,e	f de,de-fddZ/dee,e	f de-fddZ0dee,e	f de-fddZ1dee,e	f de-fddZ2d,de,dee,e	df dee, fdd Z3dee,e	f de-fd!d"Z4d-dee,e	f d#ee, de5f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dedededejdee f
dd	Z	e
d
efddZe
d
efddZe
d
efddZe
d
efddZe
d
ef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)   n/var/www/html/construction_image-detection-poc/venv/lib/python3.10/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   r0   r/   r)   r)   r*   failedL   s   
zCommandInProgress.failedc                 C   (   | j jdur|  j| j j 7  _| jS )zC
        The current output message on the standard error.
        N)r$   stderrr%   readr/   r)   r)   r*   r4   S      zCommandInProgress.stderrc                 C   r3   )zD
        The current output message on the standard output.
        N)r$   stdoutr&   r5   r/   r)   r)   r*   r7   \   r6   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: ])r0   r   r.   r$   pid)r(   r0   r)   r)   r*   __repr__e   s   zCommandInProgress.__repr__N)__name__
__module____qualname____doc__strr   
subprocessPopenr   r+   propertyboolr.   intr0   r2   r4   r7   r=   r)   r)   r)   r*   r      s2    


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)cwdr7   r4   r   )	ospathexistsjoinrD   runsplitPIPE
returncode)rI   folder_exists
git_branchr)   r)   r*   is_git_repor   s   rU   
remote_urlc                 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 )rW   rX   )resub).0remoter)   r)   r*   
<listcomp>       z"is_local_clone.<locals>.<listcomp>)rU   r   r7   rY   rZ   rP   )rI   rV   remotesr)   r)   r*   is_local_clone   s   r`   filenamec              
   C   s   t | j}t | j} ztd | g |}|j }W n tjy8 } zt	|s/W Y d}~dS t
|jd}~ww t|dkrAdS dddd}|dD ]}| D ]}||v r`d|v r`d||< qRqLt| 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   rP   r7   striprD   CalledProcessErrorrU   OSErrorr4   lenkeysallvalues)ra   rI   p
attributesexcfound_lfs_tag	attributetagr)   r)   r*   is_tracked_with_lfs   s*   


rv   c              
   C   sd   t | j}t | j} ztd | g |dd}t|j }W |S  tjy1 } zt	|j
d}~ww )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   rg   rh   r   rP   rG   rR   rD   rj   rk   r4   )ra   rI   rp   
is_ignoredrr   r)   r)   r*   is_git_ignored   s   


rz   c                 C   s|   z3t | d}|d}W d   n1 sw   Y  th dttdddh B }t|d|W S  ty=   Y dS w )	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rangerG   	translateUnicodeDecodeError)ra   fcontent
text_charsr)   r)   r*   is_binary_file   s    r   .patternc              
   C   sh   z!t d | g |}t|j r|j d}W |S g }W |S  tjy3 } zt|jd}~ww )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 -more   N)	r   rP   rl   r7   ri   rD   rj   EnvironmentErrorr4   )r   rI   rp   filesrr   r)   r)   r*   files_to_be_staged   s   
r   c              
   C   sL   zt d|  W dS  tjy% } zd|jv rtdW Y d}~dS d}~ww )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   rD   rj   r4   rk   )rI   rr   r)   r)   r*   is_tracked_upstream
  s   

r   upstreamc              
   C   sP   zt d|pd | }t|jdd W S  tjy' } zt|jd}~ww )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!   re   r   N)r   rl   r7   rP   rD   rj   r   r4   )rI   r   r-   rr   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@   rA   r   __annotations__rH   r)   r)   r)   r*   r   6  s   
 r   c               
   c   s
   t  tjkrzdV  W dS  ty   Y dS w dtjfdd} tj	dd}t
 P}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< w W d   dS 1 s~w   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                    sL  i fdd dt t f fdd}tjtjd s4 r&   dS td tjtjd r|tjd D ]h}z
|	 \}}}}W n t
y[ } zt
d	| |d}~ww |  d
| }|	d\}	}
t|	}t|
}||f}|du rt|||dddddt|	d||f< q;|d ||d   ||d< q;dS )zl
        To be launched as a separate thread with an event meaning it should stop
        the tail.
        c                     sF      D ]} | d | d j| d   | d   | d   qd S )Nr   r   )ro   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9}d}	  r   n%| }|dur1t| dks1||7 }|dr0|V  d}ntd q
W d   dS 1 sBw   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!   TNr   re   r   )r   is_setreadlinerl   ri   endswithtimesleep)ra   filecurrent_line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   unit
unit_scaleunit_divisorrh   )r   r   r   r   )r   rC   rK   rL   rM   environr   r   r   rP   
ValueError
capitalizerH   getr   r   )r   r   linestatefile_progressbyte_progressra   errordescriptioncurrent_bytestotal_bytescurrent_bytes_inttotal_bytes_intr   r)   )r   r   r   r*   output_progressJ  sH   
	
z*_lfs_log_progress.<locals>.output_progressr   r!   lfs_progresszFollowing progress in T)targetargsdaemon)loggergetEffectiveLevelr   ERROR	Exception	threadingEventrK   r   r   r   rL   rN   debugThreadstartr   )r   current_lfs_progress_valuetmpdir
exit_eventxr)   r)   r*   _lfs_log_progress<  s4   M"r   c                   @   sD  e Zd ZU dZee ed< eeddd								dhd	e	e
ef d
ee
 dee
 de	ee
f dee
 dee
 dee
 dedee fddZede
fddZdd Zedide
de	ee
df fddZdjdee
 dee
 fddZdd Zde
fd d!Zde
fd"d#Zde
fd$d%Zdee
 fd&d'Zdkd(e	e
ee
 f d)efd*d+Zd(e	e
ee
 f fd,d-Zd.d/ Zdld1e
dee
 fd2d3Zdld1e
dee
 fd4d5Zdkd6d7Zdmd8ed9efd:d;Z dnd1e
d<efd=d>Z!dod@e
fdAdBZ"			dpdCee
 dDedEede	e
e#e
ef f fdFdGZ$dkde
dHefdIdJZ%didKe
dLee
 defdMdNZ&didKe
dLee
 defdOdPZ'djdKe
dQee
 dLee
 fdRdSZ(defdTdUZ)	?			dqd@e
dDedVedEede	de
e#e
ef f f
dWdXZ*e+				drd@e
dYee
 dZedDedEef
d[d\Z,dee- fd]d^Z.d_e-ddfd`daZ/edbdc Z0eddde Z1dfdg Z2dS )s
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   s^  t |tr	t|}tj|dd tjt || _|| _	g | _
|| _|	dur)|	nt | _|   t |tr:|| _n|du rBd| _nt | _|durQ| j|d nt| jr\td ntd| jdur|du sm|du r| j| j}
|du r}|
d}|du r|
d	}|dus|dur| || |   |   |dur| 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   rC   rK   makedirsrL   rN   getcwdr   
_repo_typer   r   r   r   check_git_versionshuggingface_tokenr   r   rU   r   r   r   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   s>   zt d| jj }W |S  tjy } zt|jd}~ww )zz
        Returns the current checked out branch.

        Returns:
            `str`: Current checked out branch.
        zgit rev-parse --abbrev-ref HEADNr   r   r7   ri   rD   rj   r   r4   )r(   r-   rr   r)   r)   r*   current_branch3  s   
zRepository.current_branchc                 C   sr   zt d| jj }W n ty   tdw zt d| jj }W n ty-   tdw 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).re   N)r   r   r7   ri   FileNotFoundErrorr   r   info)r(   git_versionlfs_versionr)   r)   r*   r   B  s   zRepository.check_git_versionsr   c              
   C   s|  t |tr|n|du rdn| j}|dur|drtd| jj}||v s2d|vr}t|ddkr}t	||d\}}}|durF| d| n|}|durO|| _
|d }| j
tjv ra|tj| j
 7 }|duryt|j}|| d	| d
| d}||7 }tdd|}	ztd| j tt| jdkrtd|	 d t * tj }
| jr|
ddi t| jrdnd d| d| j|
d W d   n1 sw   Y  W dS W dS t| jstd| j d| j dt| j|rt| j d|	 d W dS td| jdd}d |	 d!|	 d"}|j dkr'td#d$|j!}|d%| 7 }t| t"j#y= } zt|j$d}~ww )&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>
        FN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.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 originrw   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   rW   rX   z'
Local path has its origin defined as: )%r   rC   r   
startswithr   r   endpointrl   rP   r   r   r   REPO_TYPES_URL_PREFIXESr   schemereplacerY   rZ   r   r   rK   listdirr   warningr   r   copyr   r   rU   r   r`   rR   r7   rD   rj   r4   )r(   r   r   r  r   	namespace	repo_namerepo_idr  clean_repo_urlr  output	error_msgclean_local_remote_urlrr   r)   r)   r*   r   Y  s~   &	"

(
	

zRepository.clone_fromc              
   C   sn   z$|durt d |g | j |dur"t d|  | j W dS W dS  tjy6 } zt|jd}~ww )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   rP   r   rD   rj   r   r4   )r(   r   r   rr   r)   r)   r*   r     s   

z(Repository.git_config_username_and_emailc              
   C   s8   z	t d| j W dS  tjy } zt|jd}~ww )z;
        Sets the git credential helper to `store`
        z"git config credential.helper storeN)r   r   rD   rj   r   r4   )r(   rr   r)   r)   r*   r     s   
z&Repository.git_credential_helper_storec              
   C   s>   zt d| j}|j W S  tjy } zt|jd}~ww )zy
        Get commit sha on top of HEAD.

        Returns:
            `str`: The current checked out commit SHA.
        zgit rev-parse HEADNr   )r(   rp   rr   r)   r)   r*   git_head_hash  s   
zRepository.git_head_hashc              
   C   sL   zt d| j}|j }tdd|W S  tjy% } zt|j	d}~ww )zp
        Get URL to origin remote.

        Returns:
            `str`: The URL of the `origin` remote.
        z"git config --get remote.origin.urlrW   rX   N)
r   r   r7   ri   rY   rZ   rD   rj   r   r4   )r(   rp   urlrr   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   Nr8   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y } zt|jd}~ww t|dkr&g 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)   )ri   r[   r0   r)   r)   r*   r]   8  s    z1Repository.list_deleted_files.<locals>.<listcomp>re   c                 S   s    g | ]}d |  d v r|qS )Dr   )rP   r  r)   r)   r*   r]   ;  s     c                 S   s   g | ]
}|  d   qS )r8   )rP   ri   r  r)   r)   r*   r]   >  s    
r   r   r7   ri   rD   rj   r   r4   rl   rP   )r(   
git_statusrr   modified_files_statusesdeleted_files_statusesdeleted_filesr)   r)   r*   list_deleted_files  s   	

zRepository.list_deleted_filespatternsra   c              
   C   sf   t |tr|g}z|D ]}td|rdnd d| | j qW dS  tjy2 } zt|jd}~ww )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   rC   r   r   rD   rj   r   r4   )r(   r%  ra   r   rr   r)   r)   r*   	lfs_trackB  s   

zRepository.lfs_trackc              
   C   s\   t |tr|g}z|D ]}td |g | j qW dS  tjy- } zt|jd}~ww )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   rC   r   rP   r   rD   rj   r   r4   )r(   r%  r   rr   r)   r)   r*   lfs_untrack[  s   

zRepository.lfs_untrackc              
   C   sX   zd}t | d| j t | dt | j W dS  tjy+ } zt|jd}~ww )zI
        HF-specific. This enables upload support of files >5GB.
        z'git config lfs.customtransfer.multipartz.path huggingface-cliz.args N)r   r   r   rD   rj   r   r4   )r(   
lfs_configrr   r)   r)   r*   r   k  s   

z Repository.lfs_enable_largefilesr   r   c                 C   s   g }|   }t|| jdD ];}||v rqtjt | j|}t|sHt|sHtj	|d }|dkr8t
d t|}|rH| | || 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
        rI      r   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   rK   rL   rN   r   rv   rz   getsizer   r  r   r&  appendr'  )r(   r   files_to_be_tracked_with_lfsr#  ra   path_to_file
size_in_mb	is_binaryr)   r)   r*   auto_track_binary_filesy  s&   


z"Repository.auto_track_binary_filesc                 C   s   g }|   }t|| jdD ]0}||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*  r   )r$  r   r   rK   rL   rN   r   r+  rv   rz   r&  r,  r'  )r(   r   r-  r#  ra   r.  r/  r)   r)   r*   auto_track_large_files  s   


z!Repository.auto_track_large_filesc              
   C   s|   z+t   td|rdnd | j}t|j W d   W dS 1 s$w   Y  W dS  tjy= } zt|j	d}~ww )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   r7   rD   rj   r   r4   )r(   recentr-   rr   r)   r)   r*   	lfs_prune  s   &
zRepository.lfs_prunerebaserf   c              
   C   s   |sdnd}|r|d7 }z$t   t|| j}t|j W d   W dS 1 s)w   Y  W dS  tjyB } zt|j	d}~ww )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	 --rebaseNr3  )r(   r6  rf   commandr-   rr   r)   r)   r*   git_pull  s   &
zRepository.git_pullauto_lfs_trackc              
   C   s   |r|  |}|| | |rtd| d ztd |g | j}td|j	 d W dS  t
jyD } zt|jd}~ww )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:
re   N)r2  extendr1  r   r  r   rP   r   r   r7   rD   rj   r   r4   )r(   r   r9  tracked_filesr-   rr   r)   r)   r*   git_add  s   


zRepository.git_addcommit files to HF hubcommit_messagec              
   C   sn   zt d |g | j}td|j d W dS  tjy6 } zt|j	dkr-t
|j	t
|jd}~ww )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:
re   r   N)r   rP   r   r   r   r7   rD   rj   rl   r4   r   )r(   r>  r-   rr   r)   r)   r*   
git_commit  s   

zRepository.git_commitr   blockingauto_lfs_prunec              
      sb  d}|r|d| 7 }t | j|}|dkr%td| d |r%td zIt < tj| tjtjd| jd |r^ 	 \}} 
 }   t|rRt| |r^tj| j||d	W d
   n1 shw   Y  W n tjy }	 zt|	jd
}	~	ww |s fdd}
td fdd|
 |r| jnd
d}| j| |  |fS |r|   |  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   r7   encodingrJ   )r  r4   Nc                     s      } | d u r
dS | S )Nr8   pollr1   r   r)   r*   r   d  s   z*Repository.git_push.<locals>.status_methodpushc                      s      d uS r>   rC  r)   rE  r)   r*   <lambda>m  s    z%Repository.git_push.<locals>.<lambda>)r   r   r   r    )r   r   r   r  r   rD   rE   rP   rQ   communicaterD  killrl   rj   r   r   r4   r   r5  r   r,  r  )r(   r   r@  rA  r7  number_of_commitsr7   r4   return_coderr   r   command_in_progressr)   rE  r*   git_push"  s\   



zRepository.git_pushr   c                 C   s   zt d| | j}td| d| j d t|j W d	S  tjyj } z>|s/t|j	zt d| | j}td| d| d t|j W n tjy^ } zt|j	d	}~ww W Y d	}~d	S d	}~ww )
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   r7   rD   rj   r   r4   )r(   r   r   r-   rr   r)   r)   r*   r   |  s(   

zRepository.git_checkouttag_namer\   c              
   C   s   |r)zt d| | jj }W n tjy" } zt|jd}~ww t|dkS zt d| jj }W n tjyF } zt|jd}~ww |	d}||v 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 tagre   r  )r(   rN  r\   r-   rr   git_tagsr)   r)   r*   
tag_exists  s    


zRepository.tag_existsc              
   C   s   d}d}|  |sd}| j ||dsd}|r8ztddd|g| jj  W n tjy7 } zt|jd}~ww |ra|raztd| d	| | jj  W dS  tjy` } zt|jd}~ww 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)r\   gitru   z-dN	git push z
 --delete )	rP  r   r   r7   ri   rD   rj   r   r4   )r(   rN  r\   delete_locallydelete_remotelyrr   r)   r)   r*   
delete_tag  s,   

 
zRepository.delete_tagr   c              
   C   s   |rddd|d|g}ndd|g}zt || jj  W n tjy- } zt|jd}~ww |rUzt d| d| | jj  W dS  tjyT } zt|jd}~ww 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.
        rQ  ru   z-az-mNrR  r  r   )r(   rN  r   r\   tag_argsrr   r)   r)   r*   add_tag  s"   

$
zRepository.add_tagc              
   C   sH   zt d| jj }W n tjy } zt|jd}~ww 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   r7   ri   rD   rj   r   r4   rl   )r(   r   rr   r)   r)   r*   is_repo_clean  s   
zRepository.is_repo_cleanclean_okc                 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r9  origin r   r@  rA  )rX  r   r   r<  r?  rM  r   )r(   r>  r@  rY  rA  r)   r)   r*   push_to_hub  s   


zRepository.push_to_hubbranchtrack_large_filesc           
      c   s,   t d| jd}t|r-t|dkr t|dd dd d nt|}td| d |dur8| j|d	d
 t| jrItd | j	d	d n
td| j
 d t }ttj|| j z[| V  W | j|d z| | W n ty }	 zdt|	vr|	W Y d}	~	nd}	~	ww z| jd| j
 ||d W n ty }	 zdt|	v rtd|	|	d}	~	ww t| dS | j|d z| | W n ty }	 zdt|	vr|	W Y d}	~	nd}	~	ww z| jd| j
 ||d W n ty }	 zdt|	v r	td|	|	d}	~	ww t| w )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)     Nr8   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 ...)r6  z@The current branch has no upstream branch. Will push to 'origin 'rZ  znothing to commitr[  r\  zcould not read UsernamezCCouldn't authenticate user for push. Did you set `token` to `True`?)r   r   rl   rC   r   r   r   r   r  r8  r   rK   r   chdirrL   rN   r<  r?  rk   rM  )
r(   r>  r^  r_  r@  rA  files_to_stagefiles_in_msgcurrent_working_directoryer)   r)   r*   commit3  s~   70







zRepository.commitc                 C   s*   t j| jtj}t j|rt|S d S r>   )rK   rL   rN   r   r   REPOCARD_NAMEisfiler   )r(   filepathr)   r)   r*   repocard_metadata_load  s   z!Repository.repocard_metadata_loaddatac                 C   s   t tj| jtj|S r>   )r   rK   rL   rN   r   r   rh  )r(   rl  r)   r)   r*   repocard_metadata_save  s   z!Repository.repocard_metadata_savec                 C      dd | j D S )z@
        Returns the asynchronous commands that failed.
        c                 S   s   g | ]	}|j d kr|qS )r   r1   r[   cr)   r)   r*   r]     r^   z.Repository.commands_failed.<locals>.<listcomp>r   r/   r)   r)   r*   commands_failed     zRepository.commands_failedc                 C   rn  )zS
        Returns the asynchronous commands that are currently in progress.
        c                 S   s   g | ]}|j s|qS r)   )r.   ro  r)   r)   r*   r]     s    z3Repository.commands_in_progress.<locals>.<listcomp>rq  r/   r)   r)   r*   commands_in_progress  rs  zRepository.commands_in_progressc                 C   s   d}| j D ]}td|j d|jj d t|j q| jr>|d dkr0td| j d |d7 }t	
d | js d	S d	S )
zr
        Blocking method: blocks all subsequent execution until all commands have
        been processed.
        r   zThe z command with PID z failed.r   zCWaiting for the following commands to finish before shutting down: r   r   N)rr  r   r   r   r$   r<   r4   rt  r  r   r   )r(   indexcommand_failedr)   r)   r*   r     s   

zRepository.wait_for_commands)NNTNNNFNr>   )NN)F)r   )FF)r   F)r=  )NTF)r=  TTF)NTTF)3r?   r@   rA   rB   r   r   r   r   r   r   rC   r   r   rG   r   r+   rF   r   r   r   r   r   r  r  r  r$  r&  r'  r   r1  r2  r5  r8  r<  r?  r	   rM  r   rP  rU  rW  rX  r]  r   rg  r   rk  rm  rr  rt  r   r)   r)   r)   r*   r     s   
 

	
l 	 #+
!"
Z  %"
$h

r   )r   Nr>   ):r   rK   rY   rD   r   r   
contextlibr   pathlibr   typingr   r   r   r   r   r	   r
   r   urllib.parser   huggingface_hubr   huggingface_hub.repocardr   r   hf_apir   r   rf   r   utilsr   r   r   r   r   r   utils._deprecationr   
get_loggerr?   r   r   rC   rG   rU   r`   rv   rz   r   r   r   rH   r   r   r   r   r)   r)   r)   r*   <module>   s<    ( 
S%&$
m