Ë
    ëÿæiGª  ã            &       óÎ  — d Z 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
mZ ddlmZmZ ddlmZ ddlmZ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 ddlmZ erddl m!Z!  ejD                  e#«      Z$dZ%dZ&de'de(e'e'f   fd„Z)e
 G d„ d«      «       Z*e
 G d„ d«      «       Z+e
 G d„ d«      «       Z,e
 G d„ d«      «       Z- e
d¬«       G d„ d«      «       Z.e
 G d„ d «      «       Z/e
 G d!„ d"«      «       Z0e
 G d#„ d$«      «       Z1de'de(e'e'f   fd%„Z2de'de3fd&„Z4e
 G d'„ d(«      «       Z5e
 G d)„ d*«      «       Z6 G d+„ d,«      Z7d-e'de8e(e'e'f      fd.„Z9d/e'dee(e'e:e;f      fd0„Z<d1d2d3e'd4e'dee(e'e:e;ef      fd5„Z=d6e;de'fd7„Z>dd8œde'd9ed:   d;e:d<e;d=e:d>e;d?e'd@e'dAe3dBe3dCe3dDedz  de5fdE„Z?	 	 	 	 	 	 	 d_dGe'dHe'd1d2dIe3dBe3dAe3dJe3dCe3dKe7dz  dLedz  de6fdM„Z@dNe6ddfdO„ZAdNe6dPe'ddfdQ„ZBdPe'de6fdR„ZCd`dNe6d1d2dSe3dLedz  ddf
dT„ZDdNe6ddfdU„ZE	 	 dadFdFdFdFdFddddddFdFdFddVœdGe'dz  dHe'dz  d1d2dIe3dBe3dAe3dJe3dCe3dWe8e'   dz  dXe8e'   dz  dYe'dz  dNe'dz  dZe'dz  d[e3dSe3d\e3d]e3e'z  dz  de6f$d^„ZFy)bzzShared logic for bucket operations.

This module contains the core buckets logic used by both the CLI and the Python API.
é    N)ÚIterator)Ú	dataclassÚfield)ÚdatetimeÚtimezone)ÚPath)ÚTYPE_CHECKINGÚAnyÚLiteralé   )Ú	constantsÚlogging)ÚBucketNotFoundError)ÚXetFileDataÚdisable_progress_barsÚenable_progress_barsÚparse_datetime)Ú
StatusLine©ÚHfApiúhf://buckets/éè  ÚpathÚreturnc                 óÀ   — | j                  dd«      }t        |«      dk  s
|d   r|d   st        d| › d�«      ‚|d   › d|d   › �}t        |«      dkD  r|d   nd}||fS )zÚSplit 'namespace/name(/optional/prefix)' into ('namespace/name', 'prefix').

    Returns (bucket_id, prefix) where prefix may be empty string.
    Raises ValueError if path doesn't contain at least namespace/name.
    Ú/é   r   r   zInvalid bucket path: 'z)'. Expected format: namespace/bucket_nameÚ )ÚsplitÚlenÚ
ValueError)r   ÚpartsÚ	bucket_idÚprefixs       úm/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/huggingface_hub/_buckets.pyÚ_split_bucket_id_and_prefixr&   5   sy   € ð �J‰J�s˜AÓ€EÜ
ˆ5ƒz�A‚~˜U 1šX¨U°1ªXÜÐ1°$°Ð7`ÐaÓbÐbØ˜‘8�*˜A˜e A™h˜ZÐ(€IÜ˜U› ašˆU�1ŠX¨R€FØ�fÐÐó    c                   óJ   — e Zd ZU dZeed<   eed<   eed<   eed<   eed<   d„ Z	y)	Ú
BucketInfoaß  
    Contains information about a bucket on the Hub. This object is returned by [`bucket_info`] and [`list_buckets`].

    Attributes:
        id (`str`):
            ID of the bucket.
        private (`bool`):
            Is the bucket private.
        created_at (`datetime`):
            Date of creation of the bucket on the Hub.
        size (`int`):
            Size of the bucket in bytes.
        total_files (`int`):
            Total number of files in the bucket.
    ÚidÚprivateÚ
created_atÚsizeÚtotal_filesc                 ó*  — |j                  d«      | _        |j                  d«      | _        t        |j                  d«      «      | _        |j                  d«      | _        |j                  d«      | _         | j                  j                  di |¤Ž y )Nr*   r+   Ú	createdAtr-   Ú
totalFiles© )	Úpopr*   r+   r   r,   r-   r.   Ú__dict__Úupdate)ÚselfÚkwargss     r%   Ú__init__zBucketInfo.__init__[   so   € Ø—*‘*˜TÓ"ˆŒØ—z‘z )Ó,ˆŒÜ(¨¯©°KÓ)@ÓAˆŒØ—J‘J˜vÓ&ˆŒ	Ø!Ÿ:™: lÓ3ˆÔØˆ�‰×ÑÑ&˜vÓ&r'   N)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__Úboolr   Úintr8   r2   r'   r%   r)   r)   C   s)   … ñð  	ƒGØƒMØÓØ
ƒIØÓó'r'   r)   c                   ó¸   — e Zd ZU eez  ez  ed<   eed<    ed¬«      Zedz  ed<    ed¬«      Z	e
dz  ed<    ed¬«      Ze
ed	<    ed¬«      Zedz  ed
<   dd„Zy)Ú_BucketAddFileÚsourceÚdestinationN©ÚdefaultÚxet_hashr-   F©ÚinitÚmtimeÚcontent_typec                 óð  — d | _         t        | j                  t        t        f«      r't        j                  | j                  «      d   | _         | j                   €'t        j                  | j                  «      d   | _         t        t        | j                  t        «      s6t        j                  j                  | j                  «      dz  «      | _        y t        j                  «       dz  «      | _        y ©Nr   r   )rK   Ú
isinstancerC   r=   r   Ú	mimetypesÚ
guess_typerD   r@   ÚbytesÚosr   ÚgetmtimeÚtimerJ   ©r6   s    r%   Ú__post_init__z_BucketAddFile.__post_init__n   s²   € Ø ˆÔÜ�d—k‘k¤C¬ ;Ô/Ü )× 4Ñ 4°T·[±[Ó AÀ!Ñ DˆDÔØ×ÑÐ$Ü )× 4Ñ 4°T×5EÑ5EÓ FÀqÑ IˆDÔäÜ8BÀ4Ç;Á;ÔPUÔ8VŒB�G‰G×Ñ˜TŸ[™[Ó)¨DÑ0ó
ˆ�
Ü\`×\eÑ\eÓ\gÐjnÑ\nó
ˆ�
r'   ©r   N)r9   r:   r;   r=   r   rQ   r>   r   rG   r-   r@   rJ   rK   rV   r2   r'   r%   rB   rB   d   sd   … à�$‰J˜ÑÓØÓá ¨Ô.€Hˆc�D‰jÓ.Ù TÔ*€Dˆ#�‰*Ó*Ù˜EÔ"€Eˆ3Ó"Ù$¨%Ô0€L�#˜‘*Ó0ô	
r'   rB   c                   óž   — e Zd ZU eed<   eed<   eed<   eed<    ed¬«      Zedz  ed<    ed¬	«      Zeed
<    ed¬	«      Z	edz  ed<   dd„Z
y)Ú_BucketCopyFilerD   rG   Úsource_repo_typeÚsource_repo_idNrE   r-   FrH   rJ   rK   c                 óœ   — t        j                  | j                  «      d   | _        t	        t        j
                  «       dz  «      | _        y rM   )rO   rP   rD   rK   r@   rT   rJ   rU   s    r%   rV   z_BucketCopyFile.__post_init__„   s7   € Ü%×0Ñ0°×1AÑ1AÓBÀ1ÑEˆÔÜœŸ™› tÑ+Ó,ˆ�
r'   rW   )r9   r:   r;   r=   r>   r   r-   r@   rJ   rK   rV   r2   r'   r%   rY   rY   z   sS   … àÓØƒMØÓØÓÙ TÔ*€Dˆ#�‰*Ó*Ù˜EÔ"€Eˆ3Ó"Ù$¨%Ô0€L�#˜‘*Ó0ô-r'   rY   c                   ó   — e Zd ZU eed<   y)Ú_BucketDeleteFiler   N)r9   r:   r;   r=   r>   r2   r'   r%   r^   r^   ‰   s   … à
„Ir'   r^   T)Úfrozenc                   ó&   — e Zd ZU dZeed<   eed<   y)ÚBucketFileMetadataa%  Data structure containing information about a file in a bucket.

    Returned by [`get_bucket_file_metadata`].

    Args:
        size (`int`):
            Size of the file in bytes.
        xet_file_data (`XetFileData`):
            Xet information for the file (hash and refresh route).
    r-   Úxet_file_dataN)r9   r:   r;   r<   r@   r>   r   r2   r'   r%   ra   ra   Ž   s   … ñ	ð ƒIØÔr'   ra   c                   ó†   — e Zd ZU dZeed<   dZeed<    ed¬«      Zeed<    ed¬«      Z	eed<    ed¬«      Z
eed	<   dd„Zy
)Ú	BucketUrla¾  Describes a bucket URL on the Hub.

    `BucketUrl` is returned by [`create_bucket`]. At initialization, the URL is parsed to populate properties:
    - endpoint (`str`)
    - namespace (`str`)
    - bucket_id (`str`)
    - url (`str`)
    - handle (`str`)

    Args:
        url (`str`):
            String value of the bucket url.
        endpoint (`str`, *optional*):
            Endpoint of the Hub. Defaults to <https://huggingface.co>.
    Úurlr   ÚendpointFrH   Ú	namespacer#   ÚhandleNc                 óª  — | j                   xs t        j                  | _         | j                  j	                  | j                   d«      j                  d«      }|j                  d«      r|t        d«      d  }t        |«      \  }}|rt        d| j                  › �«      ‚|j                  d«      d   | _        || _        d| j                  › �| _        y )Nr   r   zbuckets/zUnable to parse bucket URL: r   r   )rf   r   ÚENDPOINTre   ÚreplaceÚstripÚ
startswithr    r&   r!   r   rg   r#   rh   )r6   Úurl_pathr#   r$   s       r%   rV   zBucketUrl.__post_init__·   s¶   € ØŸ™Ò;¬×);Ñ);ˆŒð —8‘8×#Ñ# D§M¡M°2Ó6×<Ñ<¸SÓAˆà×Ñ˜zÔ*Ø¤ J£Ð 1Ð2ˆHÜ7¸ÓAÑˆ	�6ÙÜÐ;¸D¿H¹H¸:ÐFÓGÐGØ"Ÿ™¨Ó-¨aÑ0ˆŒØ"ˆŒà% d§n¡nÐ%5Ð6ˆ�r'   rW   )r9   r:   r;   r<   r=   r>   rf   r   rg   r#   rh   rV   r2   r'   r%   rd   rd   Ÿ   sJ   … ñð  
ƒHØ€HˆcÓÙ Ô&€IˆsÓ&Ù Ô&€IˆsÓ&Ù˜UÔ#€FˆCÓ#ô7r'   rd   c                   óf   — e Zd ZU dZed   ed<   eed<   eed<   eed<   edz  ed<   edz  ed	<   d
„ Z	y)Ú
BucketFilez«
    Contains information about a file in a bucket on the Hub. This object is returned by [`list_bucket_tree`].

    Similar to [`RepoFile`] but for files in buckets.
    ÚfileÚtyper   r-   rG   NrJ   Úuploaded_atc                 óX  — |j                  d«      | _        |j                  d«      | _        |j                  d«      | _        |j                  d«      | _        |j                  dd «      }|rt        |«      nd | _        |j                  dd «      }|rt        |«      | _        y d | _        y )Nrr   r   r-   ÚxetHashrJ   Ú
uploadedAt)r3   rr   r   r-   rG   r   rJ   rs   )r6   r7   rJ   rs   s       r%   r8   zBucketFile.__init__×   sˆ   € Ø—J‘J˜vÓ&ˆŒ	Ø—J‘J˜vÓ&ˆŒ	Ø—J‘J˜vÓ&ˆŒ	ØŸ
™
 9Ó-ˆŒØ—
‘
˜7 DÓ)ˆÙ.3”^ EÔ*¸ˆŒ
Ø—j‘j ¨tÓ4ˆÙ:Eœ>¨+Ó6ˆÕÈ4ˆÕr'   )
r9   r:   r;   r<   r   r>   r=   r@   r   r8   r2   r'   r%   rp   rp   È   s<   … ñð �&‰/ÓØ
ƒIØ
ƒIØƒMØ�d‰?ÓØ˜D‘Ó óPr'   rp   c                   óB   — e Zd ZU dZed   ed<   eed<   edz  ed<   d„ Zy)ÚBucketFolderz¸
    Contains information about a directory in a bucket on the Hub. This object is returned by [`list_bucket_tree`].

    Similar to [`RepoFolder`] but for directories in buckets.
    Ú	directoryrr   r   Nrs   c                 ó  — |j                  d«      | _        |j                  d«      | _        |j                  dd «      xs |j                  dd «      }|r)t        |t        «      r|| _        y t        |«      | _        y d | _        y )Nrr   r   rv   rs   )r3   rr   r   rN   r   r   rs   )r6   r7   rs   s      r%   r8   zBucketFolder.__init__î   s|   € Ø—J‘J˜vÓ&ˆŒ	Ø—J‘J˜vÓ&ˆŒ	Ø—j‘j ¨tÓ4ÒW¸¿
¹
À=ÐRVÓ8Wˆñ ô ' {´HÔ=ˆ[ð 	ÕÜCQÐR]ÓC^ð 	Õð ð 	Õr'   )	r9   r:   r;   r<   r   r>   r=   r   r8   r2   r'   r%   rx   rx   â   s(   … ñð �+Ñ
ÓØ
ƒIØ˜D‘Ó ó
r'   rx   c                 ó’   — | j                  t        «      st        d| › dt        › �«      ‚t        | j	                  t        «      «      S )zÝParse a bucket path like hf://buckets/namespace/bucket_name/prefix into (bucket_id, prefix).

    Returns:
        tuple: (bucket_id, prefix) where bucket_id is "namespace/bucket_name" and prefix may be empty string.
    zInvalid bucket path: z. Must start with )rm   ÚBUCKET_PREFIXr!   r&   Úremoveprefix©r   s    r%   Ú_parse_bucket_pathr   þ   s@   € ð �?‰?œ=Ô)ÜÐ0°°Ð6HÌÈÐXÓYÐYÜ& t×'8Ñ'8¼Ó'GÓHÐHr'   c                 ó,   — | j                  t        «      S )z!Check if a path is a bucket path.)rm   r|   r~   s    r%   Ú_is_bucket_pathr�   	  s   € à�?‰?œ=Ó)Ð)r'   c                   óŠ   — e Zd ZU dZed   ed<   eed<   dZedz  ed<   dZ	eed<   dZ
edz  ed	<   dZedz  ed
<   dZedz  ed<   y)ÚSyncOperationz,Represents a sync operation to be performed.)ÚuploadÚdownloadÚdeleteÚskipÚactionr   Nr-   r   ÚreasonÚlocal_mtimeÚremote_mtimeÚbucket_file)r9   r:   r;   r<   r   r>   r=   r-   r@   r‰   rŠ   r‹   rŒ   rp   r2   r'   r%   rƒ   rƒ     sY   … á6àÐ:Ñ;Ó;Ø
ƒIØ€Dˆ#�‰*ÓØ€FˆCÓØ"€K��t‘Ó"Ø#€L�#˜‘*Ó#Ø%)€K�˜dÑ"Ô)r'   rƒ   c                   ón   — e Zd ZU dZeed<   eed<   eed<    ee¬«      Zee	   ed<   de
eeez  f   fd„Zy	)
ÚSyncPlanz Represents a complete sync plan.rC   ÚdestÚ	timestamp)Údefault_factoryÚ
operationsr   c                 ó*  — t        d„ | j                  D «       «      }t        d„ | j                  D «       «      }t        d„ | j                  D «       «      }t        d„ | j                  D «       «      }t        d„ | j                  D «       «      }|||||dœS )Nc              3   ó@   K  — | ]  }|j                   d k(  sŒd–— Œ y­w)r„   r   N©rˆ   ©Ú.0Úops     r%   Ú	<genexpr>z#SyncPlan.summary.<locals>.<genexpr>*  ó   è ø€ ÐK¡/˜B°R·Y±YÀ(Ó5J”a¡/ùó   ‚—c              3   ó@   K  — | ]  }|j                   d k(  sŒd–— Œ y­w)r…   r   Nr•   r–   s     r%   r™   z#SyncPlan.summary.<locals>.<genexpr>+  s   è ø€ ÐO¡O˜b°r·y±yÀJÓ7Nœ¡Oùr›   c              3   ó@   K  — | ]  }|j                   d k(  sŒd–— Œ y­w)r†   r   Nr•   r–   s     r%   r™   z#SyncPlan.summary.<locals>.<genexpr>,  rš   r›   c              3   ó@   K  — | ]  }|j                   d k(  sŒd–— Œ y­w)r‡   r   Nr•   r–   s     r%   r™   z#SyncPlan.summary.<locals>.<genexpr>-  s   è ø€ ÐG¡˜"°2·9±9ÀÓ3F”A¡ùr›   c              3   óZ   K  — | ]#  }|j                   d v sŒ|j                  xs d–— Œ% y­w)©r„   r…   r   N)rˆ   r-   r–   s     r%   r™   z#SyncPlan.summary.<locals>.<genexpr>.  s'   è ø€ Ðg±¨"À2Ç9Á9ÐPfÒCf˜Ÿ™š A›±ùs   ‚+–+)ÚuploadsÚ	downloadsÚdeletesÚskipsÚ
total_size)Úsumr’   )r6   r¡   r¢   r£   r¤   r¥   s         r%   ÚsummaryzSyncPlan.summary)  s   € ÜÑK $§/¢/ÓKÓKˆÜÑO D§O¢OÓOÓOˆ	ÜÑK $§/¢/ÓKÓKˆÜÑG §¢ÓGÓGˆÜÑg°·²ÓgÓgˆ
àØ"ØØØ$ñ
ð 	
r'   N)r9   r:   r;   r<   r=   r>   r   Úlistr’   rƒ   Údictr@   r§   r2   r'   r%   rŽ   rŽ      sA   … á*àƒKØ
ƒIØƒNÙ&+¸DÔ&A€J��]Ñ#ÓAð
˜˜c 3¨¡9˜nÑ-ô 
r'   rŽ   c            
       ój   — e Zd ZdZ	 	 	 d
dee   dz  dee   dz  deeeef      dz  fd„Zdedefd	„Z	y)ÚFilterMatcherz4Matches file paths against include/exclude patterns.NÚinclude_patternsÚexclude_patternsÚfilter_rulesc                 óF   — |xs g | _         |xs g | _        |xs g | _        y)a  Initialize the filter matcher.

        Args:
            include_patterns: Patterns to include (from --include)
            exclude_patterns: Patterns to exclude (from --exclude)
            filter_rules: Rules from filter file as list of ("+"/"-", pattern) tuples
        N©r¬   r­   r®   )r6   r¬   r­   r®   s       r%   r8   zFilterMatcher.__init__@  s+   € ð !1Ò 6°BˆÔØ 0Ò 6°BˆÔØ(Ò.¨BˆÕr'   r   r   c                 ó$  — | j                   D ]"  \  }}t        j                  ||«      sŒ|dk(  c S  | j                  D ]  }t        j                  ||«      sŒ y | j                  D ]  }t        j                  ||«      sŒ y | j                  ryy)zþCheck if a path should be included based on the filter rules.

        Filtering rules:
        - Filters are evaluated in order, first matching rule decides
        - If no rules match, include by default (unless include patterns are specified)
        Ú+FT)r®   Úfnmatchr­   r¬   )r6   r   ÚsignÚpatterns       r%   ÚmatcheszFilterMatcher.matchesQ  s‰   € ð "×.Ô.‰MˆD�'Ü�‰˜t WÕ-Ø˜s‘{Ò"ð /ð
 ×,Ô,ˆGÜ�‰˜t WÕ-Ùð -ð ×,Ô,ˆGÜ�‰˜t WÕ-Ùð -ð
 × Ò Øð r'   )NNN)
r9   r:   r;   r<   r¨   r=   Útupler8   r?   r¶   r2   r'   r%   r«   r«   =  sh   „ Ù>ð .2Ø-1Ø59ñ	/à˜s™) dÑ*ð/ð ˜s™) dÑ*ð/ð ˜5  c ™?Ñ+¨dÑ2ó	/ð"˜Cð  Dô r'   r«   Úfilter_filec                 ó¢  — g }t        | «      5 }|D ]¥  }|j                  «       }|r|j                  d«      rŒ'|j                  d«      r%|j                  d|dd j                  «       f«       Œ]|j                  d«      r%|j                  d|dd j                  «       f«       Œ“|j                  d|f«       Œ§ 	 ddd«       |S # 1 sw Y   |S xY w)zþParse a filter file and return a list of (sign, pattern) tuples.

    Filter file format:
    - Lines starting with "+" are include patterns
    - Lines starting with "-" are exclude patterns
    - Empty lines and lines starting with "#" are ignored
    Ú#r²   r   NÚ-)Úopenrl   rm   Úappend)r¸   ÚrulesÚfÚlines       r%   Ú_parse_filter_filerÁ   n  s¸   € ð €EÜ	ˆkÔ	˜aÛˆDØ—:‘:“<ˆDÙ˜4Ÿ?™?¨3Ô/ØØ�‰˜sÔ#Ø—‘˜c 4¨¨ 8§>¡>Ó#3Ð4Õ5Ø—‘ Ô%Ø—‘˜c 4¨¨ 8§>¡>Ó#3Ð4Õ5ð —‘˜c 4˜[Õ)ñ ÷ 
ð €L÷ 
ð €Lús   ŽB+CÃCÚ
local_pathc              #   ó>  K  — t         j                  j                  | «      } t         j                  j                  | «      st	        d| › �«      ‚t        j
                  | «      D ]µ  \  }}}|D ]ª  }t         j                  j                  ||«      }t         j                  j                  || «      }|j                  t         j                  d«      }t         j                  j                  |«      }t         j                  j                  |«      dz  }|||f–— Œ¬ Œ· y­w)zsList all files in a local directory.

    Yields:
        tuple: (relative_path, size, mtime_ms) for each file
    z Local path must be a directory: r   r   N)rR   r   ÚabspathÚisdirr!   ÚwalkÚjoinÚrelpathrk   ÚsepÚgetsizerS   )	rÂ   ÚrootÚ_ÚfilesÚfilenameÚ	full_pathÚrel_pathr-   Úmtime_mss	            r%   Ú_list_local_filesrÒ   ‹  sÖ   è ø€ ô —‘—‘ Ó,€JÜ�7‰7�=‰=˜Ô$ÜÐ;¸J¸<ÐHÓIÐIäŸ'™' *Ö-‰ˆˆa�ÛˆHÜŸ™Ÿ™ T¨8Ó4ˆIÜ—w‘w—‘ y°*Ó=ˆHà×'Ñ'¬¯©°Ó4ˆHÜ—7‘7—?‘? 9Ó-ˆDÜ—w‘w×'Ñ'¨	Ó2°TÑ9ˆHØ˜D (Ð*Ó*ñ ñ .ùs   ‚DDÚapir   r#   r$   c              #   ó’  K  — | j                  ||xs dd¬«      D ]¨  }t        |t        «      rŒ|j                  }|rH|j	                  |dz   «      r|t        |«      dz   d }n$||k(  rd|v r|j                  dd«      d   n|}nŒj|}|j                  r|j                  j                  «       dz  nd}||j                  ||f–— Œª y­w)	zÔList all files in a bucket with a given prefix.

    Yields:
        tuple: (relative_path, size, mtime_ms, bucket_file) for each file.
            bucket_file is the BucketFile object from list_bucket_tree.
    NT)r$   Ú	recursiver   r   éÿÿÿÿr   r   )
Úlist_bucket_treerN   rx   r   rm   r    ÚrsplitrJ   r�   r-   )rÓ   r#   r$   Úitemr   rÐ   rÑ   s          r%   Ú_list_remote_filesrÚ      sÊ   è ø€ ð ×$Ñ$ Y°v²~ÀÐQUÐ$ÖVˆÜ�dœLÔ)ØØ�y‰yˆñ Ø�‰˜v¨™|Ô,Ø¤ F£¨a¡Ð 1Ð2‘Ø˜’à69¸T±k˜4Ÿ;™; s¨AÓ.¨rÒ2Àt‘ð àˆHØ48·J²J�4—:‘:×'Ñ'Ó)¨DÒ0ÀAˆØ˜Ÿ	™	 8¨TÐ1Ó1ñ' Wùs   ‚CCrÑ   c                 ón   — t        j                  | dz  t        j                  ¬«      j	                  «       S )z3Convert mtime in milliseconds to ISO format string.r   )Útz)r   Úfromtimestampr   ÚutcÚ	isoformat)rÑ   s    r%   Ú_mtime_to_isorà   Â  s&   € ä×!Ñ! (¨T¡/´h·l±lÔC×MÑMÓOÐOr'   )rŒ   rˆ   r    Úsource_sizeÚsource_mtimeÚ	dest_sizeÚ
dest_mtimeÚsource_newer_labelÚdest_newer_labelÚignore_sizesÚignore_timesÚignore_existingrŒ   c                 ó�  — t        |dk(  r|n|«      }t        |dk(  r|n|«      }| |||dœ}|
rt        ddddœ|¤ŽS ||k7  }||z
  t        kD  }|r1|rt        d|||dœ|¤ŽS ||z
  t        kD  }|r|nd}t        dd|dœ|¤ŽS |	r|rt        d|d|dœ|¤ŽS t        ddd	dœ|¤ŽS |s|r|rdn|}t        d|||dœ|¤ŽS t        ddd
dœ|¤ŽS )a—  Compare source and dest files and return the appropriate sync operation.

    This is a unified helper for both upload and download directions.

    Args:
        path: Relative file path
        action: "upload" or "download"
        source_size: Size of the source file (bytes)
        source_mtime: Mtime of the source file (milliseconds)
        dest_size: Size of the destination file (bytes)
        dest_mtime: Mtime of the destination file (milliseconds)
        source_newer_label: Label when source is newer (e.g., "local newer" or "remote newer")
        dest_newer_label: Label when dest is newer (e.g., "remote newer" or "local newer")
        ignore_sizes: Only compare mtime
        ignore_times: Only compare size
        ignore_existing: Skip files that exist on receiver
        bucket_file: BucketFile object (for downloads only)

    Returns:
        SyncOperation describing the action to take
    r„   )r   r-   rŠ   r‹   r‡   z&exists on receiver (--ignore-existing))rˆ   r‰   )rˆ   r‰   rŒ   z
same mtimezsize differsz	same sizeÚ	identicalr2   )rà   rƒ   Ú_SYNC_TIME_WINDOW_MS)r   rˆ   rá   râ   rã   rä   rå   ræ   rç   rè   ré   rŒ   Úlocal_mtime_isoÚremote_mtime_isoÚbase_kwargsÚsize_differsÚsource_newerÚ
dest_newerÚskip_reasonr‰   s                       r%   Ú_compare_files_for_syncrô   Ç  s6  € ôH $°F¸hÒ4F¡LÈJÓW€OÜ$°6¸XÒ3E¡ZÈ<ÓXÐð ØØ&Ø(ñ	#€Kñ ÜÐk FÐ3[ÑkÐ_jÑkÐkà )Ñ+€LØ  :Ñ-Ô1EÑE€LáÙÜ Ðr¨Ð7IÐWbÑrÐfqÑrÐrà$ |Ñ3Ô7KÑKˆJÙ.8Ñ*¸lˆKÜ ÐR¨°{ÑRÀkÑRÐRÙ	ÙÜ Ðn¨°~ÐS^ÑnÐbmÑnÐnä ÐR¨°{ÑRÀkÑRÐRá™<Ù'3‘^Ð9KˆFÜ Ðf¨°vÈ;ÑfÐZeÑfÐfä ÐR¨°{ÑRÀkÑRÐRr'   FrC   r�   r†   ÚexistingÚfilter_matcherÚstatusc
                 ó€  — |xs
 t        «       }t        | «       xr t        |«      }
t        | «      xr t        |«       }|
s|st        d«      ‚t        | |t	        j
                  t        j                  «      j                  «       ¬«      }d}|
�ræt        j                  j                  | «      }t        |«      \  }}t        j                  j                  |«      st        d|› �«      ‚i }t        |«      D ]?  \  }}}|j                  |«      r||f||<   |	sŒ"|	j!                  dt#        |«      › d�«       ŒA |	r|	j%                  dt#        |«      › d�«       i }|	r	 |j'                  |«      j(                  }	 t-        |||«      D ]K  \  }}}}|j                  |«      r||f||<   |	sŒ#|�d|› �nd}|	j!                  d	t#        |«      › |› d�«       ŒM 	 |	r|	j%                  d	t#        |«      › d�«       t5        |j7                  «       «      t5        |j7                  «       «      z  }|	r|	j%                  dt#        |«      › d�«       t9        |«      D �]  }|j;                  |«      }|j;                  |«      }|rv|st|r9|j<                  j?                  tA        d||d   dtC        |d   «      ¬«      «       Œe|j<                  j?                  tA        d||d   dtC        |d   «      ¬«      «       Œž|r<|r:|\  }}|\  }}|j<                  j?                  tE        |d||||dd|||¬«      «       ŒÜ|rŒß|sŒâ|sŒå|j<                  j?                  tA        d||d   dtC        |d   «      ¬«      «       �Œ |S t        | «      \  }}t        j                  j                  |«      }i }i } |	r	 |j'                  |«      j(                  }t-        |||«      D ]P  \  }}}}!|j                  |«      r||f||<   |!| |<   |	sŒ(|�d|› �nd}|	j!                  d	t#        |«      › |› d�«       ŒR |	r|	j%                  d	t#        |«      › d�«       i }t        j                  j                  |«      rMt        |«      D ]?  \  }}}|j                  |«      r||f||<   |	sŒ"|	j!                  dt#        |«      › d�«       ŒA |	r|	j%                  dt#        |«      › d�«       t5        |j7                  «       «      t5        |j7                  «       «      z  }|	r|	j%                  dt#        |«      › d�«       t9        |«      D �]>  }|j;                  |«      }|j;                  |«      }|r†|s„|r9|j<                  j?                  tA        d||d   dtC        |d   «      ¬«      «       Œe|j<                  j?                  tA        d||d   dtC        |d   «      | j;                  |«      ¬«      «       Œ®|rL|rJ|\  }}|\  }}|j<                  j?                  tE        |d||||dd|||| j;                  |«      ¬«      «       Œü|rŒÿ|s�Œ|s�Œ|j<                  j?                  tA        d||d   dtC        |d   «      ¬«      «       �ŒA |S # t*        $ r Y �Œw xY w# t.        $ r t0        j3                  d
|› d�«       Y �ŒÔw xY w# t*        $ r Y �Œõw xY w)z‚Compute the sync plan by comparing source and destination.

    Returns:
        SyncPlan with all operations to be performed
    z[One of source or dest must be a bucket path (hf://buckets/...) and the other must be local.©rC   r�   r�   NzSource must be a directory: zScanning local directory (z files)r   r   zScanning remote bucket (zBucket 'z' not found, treating as empty.zComparing files (z paths)r‡   r   znew file (--existing)r   )rˆ   r   r-   r‰   rŠ   r„   znew filezlocal newerzremote newer)r   rˆ   rá   râ   rã   rä   rå   ræ   rç   rè   ré   r†   znot in source (--delete))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«   r�   r!   rŽ   r   Únowr   rÞ   rß   rR   r   rÄ   r   rÅ   rÒ   r¶   r5   r    ÚdoneÚbucket_infor.   Ú	ExceptionrÚ   r   ÚloggerÚdebugÚsetÚkeysÚsortedÚgetr’   r½   rƒ   rà   rô   )"rC   r�   rÓ   r†   rè   rç   rõ   ré   rö   r÷   Ú	is_uploadÚis_downloadÚplanÚremote_totalrÂ   r#   r$   Úlocal_filesrÐ   r-   rÑ   Úremote_filesrÌ   Ú	total_strÚ	all_pathsr   Ú
local_infoÚremote_infoÚ
local_sizerŠ   Úremote_sizer‹   Úbucket_file_maprŒ   s"                                     r%   Ú_compute_sync_planr    sï  € ð" $Ò6¤}£€NÜ# FÓ+Ð+ÒE´ÀÓ0E€IÜ! &Ó)ÒG´/À$Ó2GÐ.G€Ká™[ÜÐvÓwÐwäØØÜ—,‘,œxŸ|™|Ó,×6Ñ6Ó8ô€Dð  $€LÚä—W‘W—_‘_ VÓ,ˆ
Ü.¨tÓ4Ñˆ	�6ä�w‰w�}‰}˜ZÔ(ÜÐ;¸J¸<ÐHÓIÐIð ˆÜ(9¸*Ö(EÑ$ˆH�d˜HØ×%Ñ% hÔ/Ø)-¨xÐ(8�˜HÑ%ÚØ—‘Ð :¼3¸{Ó;KÐ:LÈGÐTÕUð	 )Fñ
 Ø�K‰KÐ4´S¸Ó5EÐ4FÀgÐNÔOàˆÙðØ"Ÿ™¨yÓ9×EÑE�ð		PÜ/AÀ#ÀyÐRXÖ/YÑ+�˜$ ¨!Ø!×)Ñ)¨(Ô3Ø.2°HÐ-=�L Ñ*ÚØ6BÐ6N ! L >Ñ 2ÐTV�IØ—M‘MÐ$<¼SÀÓ=NÐ<OÐPYÈ{ÐZaÐ"bÕcñ 0Zñ Ø�K‰KÐ2´3°|Ó3DÐ2EÀWÐMÔNô ˜×(Ñ(Ó*Ó+¬c°,×2CÑ2CÓ2EÓ.FÑFˆ	ÙØ�K‰KÐ+¬C°	«NÐ+;¸7ÐCÔDÜ˜9×%ˆDØ$Ÿ™¨Ó.ˆJØ&×*Ñ*¨4Ó0ˆKá¡+áà—O‘O×*Ñ*Ü%Ø#)Ø!%Ø!+¨A¡Ø#:Ü(5°jÀ±mÓ(Dôõð —O‘O×*Ñ*Ü%Ø#+Ø!%Ø!+¨A¡Ø#-Ü(5°jÀ±mÓ(Dôõñ ¡à*4Ñ'�
˜KØ,7Ñ)�˜\Ø—‘×&Ñ&Ü+Ø!Ø'Ø$.Ø%0Ø"-Ø#/Ø+8Ø)7Ø%1Ø%1Ø(7ôõò  ¢K²Fà—‘×&Ñ&Ü!Ø'Ø!Ø(¨™^Ø9Ü%2°;¸q±>Ó%Bôöða &ðv €Kô /¨vÓ6Ñˆ	�6Ü—W‘W—_‘_ TÓ*ˆ
ð ˆØ*,ˆÙðØ"Ÿ™¨yÓ9×EÑE�ô 6HÈÈYÐX^Ö5_Ñ1ˆH�d˜H kØ×%Ñ% hÔ/Ø*.°Ð)9�˜XÑ&Ø,7� Ñ)ÚØ2>Ð2J˜a ˜~Ñ.ÐPR�	Ø—‘Ð 8¼¸\Ó9JÐ8KÈIÈ;ÐV]Ð^Õ_ð 6`ñ Ø�K‰KÐ2´3°|Ó3DÐ2EÀWÐMÔNàˆÜ�7‰7�=‰=˜Ô$Ü,=¸jÖ,IÑ(�˜$ Ø!×)Ñ)¨(Ô3Ø-1°8Ð,<�K Ñ)ÚØ—M‘MÐ$>¼sÀ;Ó?OÐ>PÐPWÐ"XÕYð	 -Jñ
 Ø�K‰KÐ4´S¸Ó5EÐ4FÀgÐNÔOô ˜×)Ñ)Ó+Ó,¬s°;×3CÑ3CÓ3EÓ/FÑFˆ	ÙØ�K‰KÐ+¬C°	«NÐ+;¸7ÐCÔDÜ˜9×%ˆDØ&×*Ñ*¨4Ó0ˆKØ$Ÿ™¨Ó.ˆJá¡:áà—O‘O×*Ñ*Ü%Ø#)Ø!%Ø!,¨Q¡Ø#:Ü)6°{À1±~Ó)Fôõð —O‘O×*Ñ*Ü%Ø#-Ø!%Ø!,¨Q¡Ø#-Ü)6°{À1±~Ó)FØ(7×(;Ñ(;¸DÓ(Aôõ	ñ ¡à,7Ñ)�˜\Ø*4Ñ'�
˜KØ—‘×&Ñ&Ü+Ø!Ø)Ø$/Ø%1Ø",Ø#.Ø+9Ø)6Ø%1Ø%1Ø(7Ø$3×$7Ñ$7¸Ó$=ôõò  !£Z³Fà—‘×&Ñ&Ü!Ø'Ø!Ø'¨™]Ø9Ü$1°*¸Q±-Ó$@ôöðe &ðx €Køô] ò Úðûô #ò 	Pä�L‰L˜8 I ;Ð.MÐN×Oð	Pûô^ ò Úðús<   Å Y7 Å</Z Æ,+Z Î,Z0 Ù7	ZÚZÚ"Z-Ú,Z-Ú0	Z=Ú<Z=r  c                 ó  — d| j                   | j                  | j                  | j                  «       dœ}|j	                  t        j                  |«      dz   «       | j                  D ]Ÿ  }d|j                  |j                  |j                  dœ}|j                  �|j                  |d<   |j                  �|j                  |d<   |j                  �|j                  |d	<   |j	                  t        j                  |«      dz   «       Œ¡ y)
z1Write a sync plan as JSONL to a file-like object.Úheader)rr   rC   r�   r�   r§   Ú
Ú	operation)rr   rˆ   r   r‰   Nr-   rŠ   r‹   )rC   r�   r�   r§   ÚwriteÚjsonÚdumpsr’   rˆ   r   r‰   r-   rŠ   r‹   )r  r¿   r  r˜   Úop_dicts        r%   Ú_write_planr  ú  sÚ   € ð Ø—+‘+Ø—	‘	Ø—^‘^Ø—<‘<“>ñ€Fð ‡G�GŒD�J‰J�vÓ Ñ%Ô&ð �oŒoˆàØ—i‘iØ—G‘GØ—i‘iñ	#
ˆð �7‰7ÐØ Ÿg™gˆG�F‰OØ�>‰>Ð%Ø%'§^¡^ˆG�MÑ"Ø�?‰?Ð&Ø&(§o¡oˆG�NÑ#Ø	�‰”—
‘
˜7Ó# dÑ*Õ+ñ r'   Ú	plan_filec                 ó^   — t        |d«      5 }t        | |«       ddd«       y# 1 sw Y   yxY w)z!Save a sync plan to a JSONL file.ÚwN)r¼   r  )r  r  r¿   s      r%   Ú
_save_planr    s$   € ä	ˆi˜Ô	 Ü�D˜!Ô÷ 
×	Ñ	ús   �#£,c                 óf  — t        | «      5 }|j                  «       }ddd«       st        d| › �«      ‚t        j                  |d   «      }|j                  d«      dk7  rt        d«      ‚t        |d   |d   |d	   ¬
«      }|dd D ]™  }t        j                  |«      }|j                  d«      dk7  rŒ-|j                  j                  t        |d   |d   |j                  d«      |j                  dd«      |j                  d«      |j                  d«      ¬«      «       Œ› |S # 1 sw Y   �ŒxY w)z#Load a sync plan from a JSONL file.NzEmpty plan file: r   rr   r  z0Invalid plan file: expected header as first linerC   r�   r�   rù   r   r  rˆ   r   r-   r‰   r   rŠ   r‹   )rˆ   r   r-   r‰   rŠ   r‹   )
r¼   Ú	readlinesr!   r  Úloadsr  rŽ   r’   r½   rƒ   )r  r¿   Úlinesr  r  rÀ   r  s          r%   Ú
_load_planr#    s$  € ä	ˆiŒ˜AØ—‘“ˆ÷ 
ñ ÜÐ,¨Y¨KÐ8Ó9Ð9ô �Z‰Z˜˜a™Ó!€FØ‡z�z�&Ó˜XÒ%ÜÐKÓLÐLäØ�hÑØ�F‰^Ø˜Ñ%ô€Dð �a�b“	ˆÜ—*‘*˜TÓ"ˆØ�;‰;�vÓ +Ò-ØØ�‰×ÑÜØ˜xÑ(Ø˜V‘_Ø—[‘[ Ó(Ø—{‘{ 8¨RÓ0Ø#ŸK™K¨Ó6Ø$Ÿ[™[¨Ó8ôõ		
ð	 ð €K÷C 
‰ús   ŒD&Ä&D0Úverbosec                 ód  — t        | j                  «       xr t        | j                  «      }t        | j                  «      xr t        | j                  «       }|�r!t        j                  j                  | j                  «      }t        | j                  «      \  }}|j                  d«      }g }	g }
| j                  D �]'  }|j                  xdk(  r† t        j                  j                  ||j                  «      }|r|› d|j                  › �n|j                  }|r&t        d|j                  › d|j                  › d�«       |	j                  ||f«       Œšxdk(  rZ |r|› d|j                  › �n|j                  }|r&t        d|j                  › d|j                  › d�«       |
j                  |«       Œùdk(  sŒþ|s�Œt        d	|j                  › d|j                  › d�«       �Œ* |	s|
r�|rpg }|	r|j                  d
t        |	«      › d�«       |
r|j                  dt        |
«      › d�«       |j                  dj                  |«      j!                  «       «       |j#                  ||	xs d|
xs d¬«       yy|�r t        | j                  «      \  }}|j                  d«      }t        j                  j                  | j                  «      }t        j$                  |d¬«       g }g }| j                  D �]¤  }|j                  dk(  rãt        j                  j                  ||j                  «      }t        j$                  t        j                  j'                  |«      d¬«       |r&t        d|j                  › d|j                  › d�«       |j(                  �|j                  |j(                  |f«       ŒÃ|r|› d|j                  › �n|j                  }|j                  ||f«       Œö|j                  dk(  ret        j                  j                  ||j                  «      }|r&t        d|j                  › d|j                  › d�«       |j                  |«       �Œj|j                  dk(  s�Œ{|s�Œt        d	|j                  › d|j                  › d�«       �Œ§ t        |«      dkD  r2|r|j                  dt        |«      › d�«       |j+                  ||«       |r |r|j                  dt        |«      › d�«       |D ]—  }t        j                  j-                  |«      sŒ#t        j.                  |«       t        j                  j'                  |«      }||k7  sŒ]	 t        j0                  |«       t        j                  j'                  |«      }||k7  rŒ;Œ™ yy# t2        $ r Y Œ§w xY w)zExecute a sync plan.r   r„   z  Uploading: z (Ú)r†   z  Deleting: r‡   z  Skipping: z
uploading z filesz	deleting z, N)Úaddr†   T)Úexist_okr…   z  Downloading: r   zDownloading z	Deleting z local files)r�   rC   r�   rR   r   rÄ   r   Úrstripr’   rˆ   rÇ   Úprintr‰   r½   r    rû   Ú
capitalizeÚbatch_bucket_filesÚmakedirsÚdirnamerŒ   Údownload_bucket_filesÚexistsÚremoveÚrmdirÚOSError)r  rÓ   r$  r÷   r  r  rÂ   r#   r$   Ú	add_filesÚdelete_pathsr˜   Ú
local_fileÚremote_pathr"   Údownload_filesÚdelete_filesÚ	file_pathÚparents                      r%   Ú_execute_planr<  H  sŽ  € ä# D§K¡KÓ0Ð0ÒO´_ÀTÇYÁYÓ5O€IÜ! $§+¡+Ó.ÒQ´ÀtÇyÁyÓ7QÐ3Q€KâÜ—W‘W—_‘_ T§[¡[Ó1ˆ
Ü.¨t¯y©yÓ9Ñˆ	�6Ø—‘˜sÓ#ˆð ;=ˆ	Ø"$ˆà—/•/ˆBØ—)‘)ÝÜ!#§¡§¡¨j¸"¿'¹'Ó!B�JÙ;A V H¨A¨b¯g©g¨YÑ"7ÀrÇwÁw�KÙÜ ¨b¯g©g¨Y°b¸¿¹¸À1ÐEÔFØ×$Ñ$ j°+Ð%>Õ?ÝÙ;A V H¨A¨b¯g©g¨YÑ"7ÀrÇwÁw�KÙÜ ¨R¯W©W¨I°R¸¿	¹	°{À!ÐDÔEØ ×'Ñ'¨Õ4Ü›wÜ˜L¨¯©¨	°°B·I±I°;¸aÐ@ÖAð "ñ" ™ÙØ�ÙØ—L‘L :¬c°)«nÐ-=¸VÐ!DÔEÙØ—L‘L 9¬S°Ó->Ð,?¸vÐ!FÔGØ—‘˜DŸI™I eÓ,×7Ñ7Ó9Ô:Ø×"Ñ"ØØÒ% Ø#Ò+ tð #õ ð %ò 
Ü.¨t¯{©{Ó;Ñˆ	�6Ø—‘˜sÓ#ˆÜ—W‘W—_‘_ T§Y¡YÓ/ˆ
ô 	�‰�J¨Õ.ð EGˆØ"$ˆà—/•/ˆBØ�y‰y˜JÒ&ÜŸW™WŸ\™\¨*°b·g±gÓ>�
ä—‘œBŸG™GŸO™O¨JÓ7À$ÕGÙÜ˜O¨B¯G©G¨9°B°r·y±y°kÀÐCÔDà—>‘>Ð-Ø"×)Ñ)¨2¯>©>¸:Ð*FÕGá;A V H¨A¨b¯g©g¨YÑ"7ÀrÇwÁw�KØ"×)Ñ)¨;¸
Ð*CÕDØ—‘˜hÒ&ÜŸW™WŸ\™\¨*°b·g±gÓ>�
ÙÜ˜L¨¯©¨	°°B·I±I°;¸aÐ@ÔAØ×#Ñ# JÖ/Ø—‘˜fÔ$«Ü˜ R§W¡W I¨R°·	±	¨{¸!Ð<Ö=ð' "ô, ˆ~Ó Ò"ÙØ—‘˜l¬3¨~Ó+>Ð*?¸vÐFÔGØ×%Ñ% i°Ô@ñ ‘lØ�K‰K˜)¤C¨Ó$5Ð#6°lÐCÔDÛ%ˆIÜ�w‰w�~‰~˜iÕ(Ü—	‘	˜)Ô$äŸ™Ÿ™¨Ó3�Ø 
Ó*ðÜŸ™ Ô(Ü!#§¡§¡°Ó!8˜ð  
Ô*ñ &ðU 
øôf #ò Ùðús   Õ%4V#Ö#	V/Ö.V/c                 óö   — | j                  «       }t        d| j                  › d| j                  › �«       t        d|d   › �«       t        d|d   › �«       t        d|d   › �«       t        d	|d
   › �«       y)z!Print a summary of the sync plan.zSync plan: z -> z  Uploads: r¡   z  Downloads: r¢   z  Deletes: r£   z	  Skips: r¤   N)r§   r*  rC   r�   )r  r§   s     r%   Ú_print_plan_summaryr>  ¬  s~   € à�l‰l‹n€GÜ	ˆK˜Ÿ™�} D¨¯©¨Ð
4Ô5Ü	ˆK˜ 	Ñ*Ð+Ð
,Ô-Ü	ˆM˜' +Ñ.Ð/Ð
0Ô1Ü	ˆK˜ 	Ñ*Ð+Ð
,Ô-Ü	ˆI�g˜gÑ&Ð'Ð
(Õ)r'   )r†   rè   rç   rõ   ré   ÚincludeÚexcludeÚfilter_fromr  ÚapplyÚdry_runr$  ÚquietÚtokenr?  r@  rA  rB  rC  rD  rE  c                ód  — |�ddl m}  ||¬«      }|rù| s|rt        d«      ‚|�t        d«      ‚|rt        d«      ‚|rt        d«      ‚|rt        d	«      ‚|rt        d
«      ‚|	rt        d«      ‚|
rt        d«      ‚|rt        d«      ‚|rt        d«      ‚|rt        d«      ‚t        |«      }t	        | ¬«      }|st        |«       t        d«       |r
t        «        	 t        ||||¬«       |rt        «        	 |st        d«       |S | r|st        d«      ‚t        | «      }t        |«      }|r|rt        d«      ‚|s|st        d«      ‚|r|rt        d«      ‚|r|rt        d«      ‚|r|rt        d«      ‚|rLt        j                  j                  |«      rZt        j                  j                  |«      s;t        d|› �«      ‚t        j                  j                  | «      st        d| › �«      ‚d}|
rt        |
«      }t!        ||	|¬«      }t	        | xr | ¬«      }t#        | |||||||||¬«
      }|rt%        |t&        j(                  «       |S |r)t+        ||«       |st        |«       t        d|› �«       |S |st        |«       |j-                  «       }|d   d k(  r|d!   d k(  r|d"   d k(  r|st        d#«       |S |st        d$«       |r
t        «        	 t        ||||¬«       |rt        «        	 |st        d«       |S # |rt        «        w w xY w# |rt        «        w w xY w)%a  Sync files between a local directory and a bucket.

    This is equivalent to the ``hf buckets sync`` CLI command. One of ``source`` or ``dest`` must be a bucket path
    (``hf://buckets/...``) and the other must be a local directory path.

    Args:
        source (`str`, *optional*):
            Source path: local directory or ``hf://buckets/namespace/bucket_name(/prefix)``.
            Required unless using ``apply``.
        dest (`str`, *optional*):
            Destination path: local directory or ``hf://buckets/namespace/bucket_name(/prefix)``.
            Required unless using ``apply``.
        api ([`HfApi`]):
            The HfApi instance to use for API calls.
        delete (`bool`, *optional*, defaults to `False`):
            Delete destination files not present in source.
        ignore_times (`bool`, *optional*, defaults to `False`):
            Skip files only based on size, ignoring modification times.
        ignore_sizes (`bool`, *optional*, defaults to `False`):
            Skip files only based on modification times, ignoring sizes.
        existing (`bool`, *optional*, defaults to `False`):
            Skip creating new files on receiver (only update existing files).
        ignore_existing (`bool`, *optional*, defaults to `False`):
            Skip updating files that exist on receiver (only create new files).
        include (`list[str]`, *optional*):
            Include files matching patterns (fnmatch-style).
        exclude (`list[str]`, *optional*):
            Exclude files matching patterns (fnmatch-style).
        filter_from (`str`, *optional*):
            Path to a filter file with include/exclude rules.
        plan (`str`, *optional*):
            Save sync plan to this JSONL file instead of executing.
        apply (`str`, *optional*):
            Apply a previously saved plan file. When set, ``source`` and ``dest`` are not needed.
        dry_run (`bool`, *optional*, defaults to `False`):
            Print sync plan to stdout as JSONL without executing.
        verbose (`bool`, *optional*, defaults to `False`):
            Show detailed per-file operations.
        quiet (`bool`, *optional*, defaults to `False`):
            Suppress all output and progress bars.
        token (Union[bool, str, None], optional):
            A valid user access token. If not provided, the locally saved token will be used.

    Returns:
        [`SyncPlan`]: The computed (or loaded) sync plan.

    Raises:
        `ValueError`: If arguments are invalid (e.g., both paths are remote, conflicting options).

    Example:
        ```python
        >>> from huggingface_hub import HfApi
        >>> api = HfApi()

        # Upload local directory to bucket
        >>> api.sync_bucket("./data", "hf://buckets/username/my-bucket")

        # Download bucket to local directory
        >>> api.sync_bucket("hf://buckets/username/my-bucket", "./data")

        # Sync with delete and filtering
        >>> api.sync_bucket(
        ...     "./data",
        ...     "hf://buckets/username/my-bucket",
        ...     delete=True,
        ...     include=["*.safetensors"],
        ... )

        # Dry run: preview what would be synced
        >>> plan = api.sync_bucket("./data", "hf://buckets/username/my-bucket", dry_run=True)
        >>> plan.summary()
        {'uploads': 3, 'downloads': 0, 'deletes': 0, 'skips': 1, 'total_size': 4096}

        # Save plan for review, then apply
        >>> api.sync_bucket("./data", "hf://buckets/username/my-bucket", plan="sync-plan.jsonl")
        >>> api.sync_bucket(apply="sync-plan.jsonl")
        ```
    Nr   r   )rE  z,Cannot specify source/dest when using apply.z#Cannot specify both plan and apply.z'Cannot specify delete when using apply.z-Cannot specify ignore_times when using apply.z-Cannot specify ignore_sizes when using apply.z(Cannot specify include when using apply.z(Cannot specify exclude when using apply.z,Cannot specify filter_from when using apply.z)Cannot specify existing when using apply.z0Cannot specify ignore_existing when using apply.z(Cannot specify dry_run when using apply.)ÚenabledzExecuting plan...)r$  r÷   zSync completed.z7Both source and dest are required (unless using apply).z?Remote to remote sync is not supported. One path must be local.z?One of source or dest must be a bucket path (hf://buckets/...).z2Cannot specify both ignore_times and ignore_sizes.z1Cannot specify both existing and ignore_existing.z%Cannot specify both dry_run and plan.z!Destination must be a directory: z&Source must be an existing directory: r°   )
rC   r�   rÓ   r†   rè   rç   rõ   ré   rö   r÷   zPlan saved to: r¡   r   r¢   r£   zNothing to sync.z
Syncing...)Úhf_apir   r!   r#  r   r>  r*  r   r<  r   r�   rR   r   r0  rÅ   rÁ   r«   r  r  ÚsysÚstdoutr  r§   )rC   r�   rÓ   r†   rè   rç   rõ   ré   r?  r@  rA  r  rB  rC  r$  rD  rE  r   Ú	sync_planr÷   Úsource_is_bucketÚdest_is_bucketr®   rö   r§   s                            r%   Úsync_bucket_internalrN  »  sa  € ðF ÐÝ!á˜%Ô ˆáÙ‘TÜÐKÓLÐLØÐÜÐBÓCÐCÙÜÐFÓGÐGÙÜÐLÓMÐMÙÜÐLÓMÐMÙÜÐGÓHÐHÙÜÐGÓHÐHÙÜÐKÓLÐLÙÜÐHÓIÐIÙÜÐOÓPÐPÙÜÐGÓHÐHä˜uÓ%ˆ	Ü¨ IÔ.ˆÙÜ 	Ô*ÜÐ%Ô&áÜ!Ô#ð	'Ü˜) S°'À&ÕIáÜ$Õ&áÜÐ#Ô$àÐñ ™ÜÐRÓSÐSä& vÓ.ÐÜ$ TÓ*€Ná™NÜÐZÓ[Ð[á¡NÜÐZÓ[Ð[á™ÜÐMÓNÐNá‘OÜÐLÓMÐMá‘4ÜÐ@ÓAÐAñ Ü�7‰7�>‰>˜$Ô¬¯©¯©°dÔ(;ÜÐ@ÀÀÐGÓHÐHä�w‰w�}‰}˜VÔ$ÜÐEÀfÀXÐNÓOÐOð €LÙÜ)¨+Ó6ˆä"Ø Ø Ø!ô€Nô  E 	Ò 9°'¨kÔ:€FÜ"ØØØØØ!Ø!ØØ'Ø%Øô€Iñ Ü�IœsŸz™zÔ*ØÐáÜ�9˜dÔ#ÙÜ 	Ô*Ü�O D 6Ð*Ô+ØÐñ Ü˜IÔ&à×ÑÓ!€GØˆyÑ˜QÒ 7¨;Ñ#7¸1Ò#<ÀÈÑASÐWXÒAXÙÜÐ$Ô%ØÐáÜˆlÔáÜÔð#Ü�i ¨g¸fÕEáÜ Õ"áÜÐÔ àÐøñG Ü$Õ&ð ûñz Ü Õ"ð ús   Ã"L Ë#L  ÌLÌ L/)FFFFFNN)FN)NN)Gr<   r³   r  rO   rR   rI  rT   Úcollections.abcr   Údataclassesr   r   r   r   Úpathlibr   Útypingr	   r
   r   r   r   r   Úerrorsr   Úutilsr   r   r   r   Úutils._terminalr   rH  r   Ú
get_loggerr9   rþ   r|   rì   r=   r·   r&   r)   rB   rY   r^   ra   rd   rp   rx   r   r?   r�   rƒ   rŽ   r«   r¨   rÁ   r@   ÚfloatrÒ   rÚ   rà   rô   r  r  r  r#  r<  r>  rN  r2   r'   r%   Ú<module>rX     s\  ðñó
 Û Û Û 	Û 
Û Ý $ß (ß 'Ý ß .Ñ .ç  Ý 'ß [Ó [Ý 'ñ Ýð 
ˆ×	Ñ	˜HÓ	%€ð  €ØÐ ð cð ¨e°C¸°H©oó ð ÷'ð 'ó ð'ð@ ÷
ð 
ó ð
ð* ÷-ð -ó ð-ð ÷ð ó ðñ �$Ô÷ð ó ðð  ÷%7ð %7ó ð%7ðP ÷Pð Pó ðPð2 ÷
ð 
ó ð
ð6I˜Sð I U¨3°¨8¡_ó Ið*˜#ð * $ó *ð ÷	*ð 	*ó ð	*ð ÷
ð 
ó ð
÷8.ñ .ðb Cð ¨D°°s¸C°x±Ñ,Aó ð:+ #ð +¨(°5¸¸cÀ5¸Ñ3IÑ*Jó +ð*2˜Gð 2°ð 2¸Sð 2ÀXÈeÐTWÐY\Ð^cÐehÐThÑNiÑEjó 2ðDP˜Eð P có Pð$ #òESà
ðESð Ð(Ñ)ðESð ð	ESð
 ðESð ðESð ðESð ðESð ðESð ðESð ðESð ðESð �t‘ðESð óESðX ØØØØ!Ø+/ØñcØðcà
ðcð 
ðcð ð	cð
 ðcð ðcð ðcð ðcð " DÑ(ðcð �$‰Jðcð ócðV,�hð , dó ,ð:�Xð ¨#ð °$ó ð#˜#ð # (ó #ñVa˜ð a wð a¸ð aÈsÐUYÉzð aÐeió aðH*˜hð *¨4ó *ð  Øðnð
 ØØØØ!Ø $Ø $Ø"ØØØØØØ#ò%nØ�$‰Jðnà
�‰*ðnð 
ð	nð
 ðnð ðnð ðnð ðnð ðnð �#‰Y˜Ñðnð �#‰Y˜Ñðnð �t‘ðnð �‰*ðnð �‰:ðnð ðnð  ð!nð" ð#nð$ �#‰:˜Ñð%nð& ô'nr'   