o
    +ke                     @   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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 ddlmZ e Zd	d
lmZ d	dlmZ d	dlmZmZmZmZm Z  ddl!m"Z# ddl!m$Z% ddl&T ddl'm(Z( dd Z)diddZ*diddZ+djddZ,dd Z-diddZ.d d! Z/d"d# Z0d$d% Z1d&d' Z2d(d) Z3G d*d+ d+Z4G d,d- d-eZ5G d.d/ d/e5Z6d0d1 Z7i fd2d3Z8e8Z9e8Z:e8Z;d4d5 Z<dkd7d8Z=G d9d: d:e>Z?d;d< Z@dld?d@ZAdmdAdBZBdmdCdDZCdEdF ZDdGdH ZEG dIdJ dJZFdndKdLZGdMdN ZHG dOdP dPZIG dQdR dReIZJG dSdT dTeIZKdUdV ZLdodXdYZMdZd[ ZNd\d] ZOG d^d_ d_ejPZQddd`dadbZRdcdd ZSdedf ZTdgdh ZUdS )p    N)hexlify)CounterOrderedDict)datetimetimezone)partial)	Formatter   )create_logger   )Error)get_keys_dir)OutputTimestampformat_timeto_localtimesafe_timestampsafe_s)__version__)__version_tuple__)*)is_win32c                 C   s   t | dS )Nascii)r   decode)binary r   <usr/lib/python3.10/site-packages/borg/helpers/parseformat.py
bin_to_hex      r   utf-8surrogateescapec                 C      | du rdS |  ||S )z8decode bytes to str, with round-tripping "invalid" bytesN)r   sZcodingerrorsr   r   r   safe_decode!      r$   c                 C   r    )z8encode str to bytes, with round-tripping "invalid" bytesN)encoder!   r   r   r   safe_encode(   r%   r'   replacec                 C   s   |  d|dS )z1Replace surrogates generated by fsdecode with '?'r   r&   r   )r"   r#   r   r   r   remove_surrogates/      r*   c                 C   s   |  dddS )z?Evaluate literal escape sequences in a string (eg `\n` -> `
`).r   backslashreplacezunicode-escaper)   )r"   r   r   r   eval_escapes4   r+   r-   c                 C   s2   |D ]}t | |tr| | ||| |< q| S N)
isinstancegetbytesr   )dkeysencodingr#   keyr   r   r   decode_dict9   s
   r6   c                 C   s"   t | }|dkrtd|  |S )z#argparse type for positive integersr   z"A positive integer is required: %s)intargparseArgumentTypeError)valueZ	int_valuer   r   r   positive_int_validator@   s   r;   c                 C   s   dddddd}|  t| r| dd }| d }nd	d
 t| dd dD }td| d  d|z
t|||  }W n tyM   d}Y nw |dkrYtd| |S )zDConvert a string representing a valid interval to a number of hours.r         i  i8"  )Hr2   wmyNc                 S   s   g | ]\}}|qS r   r   ).0kvr   r   r   
<listcomp>Q       zinterval.<locals>.<listcomp>c                 S   s   | d S Nr   r   )tr   r   r   <lambda>Q   s    zinterval.<locals>.<lambda>)r5   zUnexpected interval time unit "z": expected one of r   zCUnexpected interval number "%s": expected an integer greater than 0)	endswithtupler3   sorteditemsr8   r9   r7   
ValueError)r"   Z
multipliernumbersuffixZrangeshoursr   r   r   intervalH   s$   
rS   c                 C   sd  dd }|   d}t|}|dkr|dd |d  }|tkr]d|  kr,dkr]n n/t|d	 }|dkr>t|d nd}|d
k rI|dd |tksQ|tkrX|dt d |||fS |dkrg|d	krgtS |tkro|dkss|dkrdd ||d d  D \}}}	}
||	  kr|ksn |dd |dk r|dd |dkr|dd t|||	|
fS t	
d)Nc                 S   s   |rt | t|  d S r.   )r8   r9   loggerwarning)msgZrejectr   r   r   reject_or_warnb   s   
z%ChunkerParams.<locals>.reject_or_warn,r   zno chunker params givenTr	      r   @   z)block_size must not be less than 64 BytesFz=block_size and header_size must not exceed MAX_DATA_SIZE [%d]default      c                 s   s    | ]}t |V  qd S r.   )r7   )rC   pr   r   r   	<genexpr>~   s    z ChunkerParams.<locals>.<genexpr>z.required: chunk_min <= chunk_mask <= chunk_max   zLmin. chunk size exponent must not be less than 6 (2^6 = 64B min. chunk size)   zOmax. chunk size exponent must not be more than 23 (2^23 = 8MiB max. chunk size)zinvalid chunker params)stripsplitlenlowerZCH_FIXEDr7   ZMAX_DATA_SIZEZCHUNKER_PARAMSZ
CH_BUZHASHr8   r9   )r"   rW   paramscountZalgo
block_sizeheader_sizeZ	chunk_minZ	chunk_maxZ
chunk_maskwindow_sizer   r   r   ChunkerParamsa   s4   
 

"



rk   c                    s   t ddddddd d}t|  d	}|t ks'td
d	t   fdd|D }dt|}||vrEtdd	| |S )Ncr@   r"   irr2   )ctimemtimesizeinodeZrechunkdisabled)ZcisZimscsmsZcrmrr2   r"   rX   z0cache mode must be a comma-separated list of: %sc                    s   h | ]} | qS r   r   )rC   entryZENTRIES_MAPr   r   	<setcomp>   rG   z!FilesCacheMode.<locals>.<setcomp> z#cache mode short must be one of: %s)dictsetrb   rc   r8   r9   joinrM   )r"   ZVALID_MODESentriesZshort_entriesmoder   rx   r   FilesCacheMode   s   r   c                    sD      D ]\}}t|}td| d| d fdd| } q| S )z
    Apply format.format_map(mapping) while preserving unknown keys

    Does not support attribute access, indexing and ![rsa] conversions
    z(?<!\{)((\{z\})|(\{z:[^\}]*\}))c                    s   |  d S rH   )group
format_map)matchmappingr   r   rJ      s    z partial_format.<locals>.<lambda>)rN   reescapesub)formatr   r5   r:   r   r   r   partial_format   s   

r   c                   @   s   e Zd Zdd Zdd ZdS )DatetimeWrapperc                 C   s
   || _ d S r.   )dt)selfr   r   r   r   __init__   s   
zDatetimeWrapper.__init__c                 C   s   |dkrt }| j|S Nrz   )ZISO_FORMAT_NO_USECSr   
__format__r   format_specr   r   r   r      s   zDatetimeWrapper.__format__N)__name__
__module____qualname__r   r   r   r   r   r   r      s    r   c                   @      e Zd ZdZdS )PlaceholderErrorz)Formatting Error: "{}".format({}): {}({})Nr   r   r   __doc__r   r   r   r   r          r   c                   @   r   )InvalidPlaceholderz&Invalid placeholder "{}" in string: {}Nr   r   r   r   r   r      r   r   c              
   C   sr   t  | D ]\}}}}|sq|s||vrt|| qz| |W S  ty8 } zt| ||jjt|d }~ww r.   )	r   parser   r   	Exceptionr   	__class__r   str)r   data_r5   
conversioner   r   r   format_line   s   
r   c                 C   s   ddl m}m}m} ttj}t	 |d
t|d|t|dt|| tt tdtdd  dtdd  dtdd	  d
|}t| |S )z/Replace placeholders in text with their values.r	   )fqdnhostnamegetosusername.Nz%dr   z%d.%dz%d.%d.%drY   )pidr   zreverse-fqdnr   nowutcnowuseruuid4ZborgversionZ	borgmajorZ	borgminorZ	borgpatch)platformr   r   r   r   r   r   utcosgetpidr}   reversedrc   r   
astimezoner   uuidr   borg_versionborg_version_tupler   )text	overridesr   r   r   Zcurrent_timer   r   r   r   replace_placeholders   s$   

r   c                 C   sF   ddl m} | dD ]}||vrtd| q| ddddS )	Nr   )AI_HUMAN_SORT_KEYSrX   zInvalid sort key: %s	timestamptsarchivename)manifestr   rc   r8   r9   r(   )r   r   tokenr   r   r   
SortBySpec   s   r   Fc                 C   s   |rt nt}|| dd||dS )z2Format file size into a human friendly format
    B )rQ   sep	precisionsign)sizeof_fmt_iecsizeof_fmt_decimal)rE   r   r   iecfnr   r   r   format_file_size   s   r   c                   @   s   e Zd ZdddZdd ZdS )FileSizeFc                 C   s   t | |}||_|S r.   )r7   __new__r   )clsr:   r   objr   r   r   r      s   zFileSize.__new__c                 C   s   t t| | jd|S )Nr   )r   r7   r   r   r   r   r   r   r         zFileSize.__format__N)F)r   r   r   r   r   r   r   r   r   r      s    
r   c                 C   st   | st | S | d }d}z||d |d |d |d d| }| dd } W n ty1   d	}Y nw t t| | S )
z,Return int from file size (1234, 55G, 1.7T).rB     r	   rY   r]   r\   )KMGTPNr   )r7   KeyErrorfloat)r"   rQ   powerZfactorr   r   r   parse_file_size   s$   r   r   rz   c           
      C   sp   |r| dkrdnd}d}d}|d d D ]}	t t| ||k r! n| t| } |}q|d }	|| ||||	|S )Nr   +rz   z{0:{1}.{2}f}{3}{4}{5}rB   )absroundr   r   )
numrQ   unitsr   r   r   r   fmtZprecZunitr   r   r   
sizeof_fmt  s   r   c              	   C      t | ||||g dddS )N)	rz   ZKiZMiZGiZTiPiZEiZZiZYii   rQ   r   r   r   r   r   r   r   rQ   r   r   r   r   r   r   r        r   c              	   C   r   )N)	rz   rD   r   r   r   r   EZYr   r   r   r   r   r   r   r   "  r   r   c                 C   s    d| j tt| jt| jf S )Nz%-36s %s [%s])r   r   r   r   r   id)r   r   r   r   format_archive'  s
   r   c                 C   s   t d| }dd |D S )Nz *, *c                 S   s   g | ]}|d kr|qS )rz   r   )rC   itemr   r   r   rF   1  s    z*parse_stringified_list.<locals>.<listcomp>)r   rc   )r"   lr   r   r   parse_stringified_list/  s   r   c                   @   s  e Zd ZdZd Z Z Z Z ZZ	dZ
dZdZdZdZdZed	e
 e d
 e e ejZede e ejZede
 e d e e ejZede ejZede ejZdi fddZi fddZdd Zdd Zdd Zdd Zedd Zdd  Z d!d" Z!d#d$ Z"dS )%Locationz8Object representing a repository / archive location
    Nz%
        (?:(?P<user>[^@:/]+)@)?
    z
        (?!(:|//|ssh://))                                   # not starting with ":" or // or ssh://
        (?P<path>([^:]|(:(?!:)))+)                          # any chars, but no "::"
        z
        (?P<path>(([^/]*)/([^:]|(:(?!:)))+))                # start opt. servername, then /, then any chars, but no "::"
        zq
        (?P<path>(/([^:]|(:(?!:)))+))                       # start with /, then any chars, but no "::"
        z
        (?:
            ::                                              # "::" as separator
            (?P<archive>[^/]+)                              # archive name must not contain "/"
        )?$z
        (?P<host>(
            (?!\[)[^:/]+(?<!\])     # hostname or v4 addr, not containing : or / (does not match v6 addr: no brackets!)
            |
            \[[0-9a-fA-F:.]+\])     # ipv6 address in brackets
        )
    zR
        (?P<proto>ssh)://                                       # ssh://
        z                 # user@  (optional), host name or address
        (?::(?P<port>\d+))?                                     # :port (optional)
        zS
        (?P<proto>file)://                                      # file://
        z
        (
            z             # user@  (optional), host name or address
            :                                                   # : (required!)
        )?                                                      # user@host: part is optional
        a                                  # the repo part is fetched from BORG_REPO
        (?:::$)                                             # just "::" is ok (when a pos. arg is required, no archive)
        |                                                   # or
        a^  
        (?:file://)?                                        # optional file protocol
        (?P<path>
            (?:[a-zA-Z]:)?                                  # Drive letter followed by a colon (optional)
            (?:[^:]+)                                       # Anything which does not contain a :, at least one character
        )
        rz   c                 C   s   |  ||std| j d S )NzInvalid location format: "%s")r   rO   	processed)r   r   r   r   r   r   r     s   zLocation.__init__c                 C   s   || _ t|| | _}| |}|rdS | j|}|sdS tjd}|d u r*dS t||}| |}|	d| _
| j
s?|n|| j  | _ | j
sM|| _|S | d| j
 | _|S )NTFZ	BORG_REPOr   ::)rawr   r   _parseenv_rer   r   environr0   r   r   )r   r   r   validr@   Zrepo_rawZrepor   r   r   r     s&   


zLocation.parsec                 C   sL  dd }t r!| j|}|rd| _|d| _|d| _dS dS | j|}|rZ|d| _|d	| _|d
| _	|drGt
|dpHd | _||d| _|d| _dS | j|}|rx|d| _||d| _|d| _dS | j|}|r|d	| _|d
| _	||d| _|d| _| j	rdpd| _dS dS )Nc                 S   s&   |  d}tj| } |rd|  S | S )N/./z/.)
startswithr   pathnormpath)r^   relativer   r   r   normpath_special  s   
z)Location._parse.<locals>.normpath_specialfiler   r   TFprotor   hostportZssh)r   win_file_rer   r   r   r   r   ssh_rer   _hostr7   r  file_rescp_re)r   r   r   r@   r   r   r   r     sB   zLocation._parsec                 C   s>   d| j  d| j d| j d| j d| j d| j g}d|S )Nzproto=%rzuser=%rzhost=%rzport=%rzpath=%rz
archive=%rz, )r   r   r  r  r   r   r}   )r   rN   r   r   r   __str__  s   
zLocation.__str__c                 C   s`   t dd| jd}| jdkrt dd| jd | }t|dkr(|d d }tjt	 |S )Nz[^\w]r   r   __d   )
r   r   r   rb   r   r  rd   r   r}   r   )r   r   r   r   r   to_key_filename  s   
zLocation.to_key_filenamec                 C   s   d|  S )NzLocation(%s)r   r   r   r   r   __repr__     zLocation.__repr__c                 C   s    | j d ur| j ddS d S )N[])r  lstriprstripr  r   r   r   r    s   
zLocation.hostc                 C   s   | j dkr| jS | jr| jdrd| j }n| jr&| jds&d| j }n| j}d| jr4| j dnd| j| jrBd| j |S d|S )	Nr   ~/r   zssh://{}{}{}{}@rz   :)r   r   r   r   r   r  r  )r   r   r   r   r   canonical_path  s   
zLocation.canonical_pathc                 C   s"   t | jt|d t|ddS )N)r   r   )r   )r   r   r   r   )r   r   r   r   r   with_timestamp  s   
zLocation.with_timestampc                 C   s8   t | j}d |_|jdd |_|jdd |_|S )Nr   r   )r   r   r   rc   r   )r   locr   r   r   omit_archive  s
   
zLocation.omit_archive)#r   r   r   r   r   r   r  r  r   r   Zoptional_user_reZscp_path_reZfile_path_reZabs_path_reZoptional_archive_reZhost_rer   compileVERBOSEr  r  r  r   r  r   r   r   r  r  r  propertyr  r  r  r  r   r   r   r   r   4  s~    		+
r   c                    s    fdd}|S )Nc              
      s   zt | }W n ty } ztt|d d }~ww  du r)|js)td|   du r7|jr7td|  d urR|jkrRdkrKtd|  td|  |S )NTz"%s": No archive specifiedFz!"%s": No archive can be specifiedr   z"%s": Repository must be localz"%s": Repository must be remote)r   rO   r8   r9   r   r   r   )r   r  errr   r   r   r   	validator  s   z%location_validator.<locals>.validatorr   )r   r   r   r   r  r   location_validator  s   r!  c                  C   s   dd } | S )Nc                 S   s.   t | } d| v sd| v s| std|  | S )Nr  r   zInvalid archive name: "%s")r   r8   r9   )r   r   r   r   r     s   z(archivename_validator.<locals>.validatorr   )r   r   r   r   archivename_validator  s   r"  c                   @   s@   e Zd ZdddddejejdZdd Zd	d
 Zedd Z	dS )BaseFormatter
r   	 )ZLFSPACEZTABCRNULNEWLINENLc                 C   s   t r.   )NotImplementedErrorr   r   r   r   r   get_item_data3  s   zBaseFormatter.get_item_datac                 C   s   | j | |S r.   )r   r   r/  r.  r   r   r   format_item6  s   zBaseFormatter.format_itemc                   C      dS )Nz- NEWLINE: OS dependent line separator
- NL: alias of NEWLINE
- NUL: NUL character for creating print0 / xargs -0 like output, see barchive and bpath keys below
- SPACE
- TAB
- CR
- LFr   r   r   r   r   	keys_help9  s   zBaseFormatter.keys_helpN)
r   r   r   r   linesep
FIXED_KEYSr/  r0  staticmethodr2  r   r   r   r   r#  '  s    r#  c                   @   s   e Zd Zddddddddd	d
ddddZdZedd Zedd ZdddddZdd Z	dd Z
edd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(S ))ArchiveFormatterzUarchive name interpreted as text (might be missing non-text characters, see barchive)zalias of "archive"z;verbatim archive name, can contain any character except NULzXarchive comment interpreted as text (might be missing non-text characters, see bcomment)z>verbatim archive comment, can contain any character except NULz'time (start) of creation of the archivezalias of "start"z%time (end) of creation of the archivez1command line which was used to create the archivezinternal ID of the archivez2hostname of host on which this archive was createdz)username of user who created this archivez(TAM authentication state of this archive)r   r   barchivecommentbcommentstarttimeendcommand_liner   r   usernametam))r   r   r7  r8  r9  r   r?  )r:  r;  r<  r=  )r   r>  c              	   C   s`   ddl m} |ddtdddtjd}| dd d d }g }||j  |||  |S )Nr   )ArchiveInfoarchivenames    i  tzinforz   )	r   r@  r   r   r   extend	call_keysr3   r/  )r   r@  Zfake_archive_info	formatterr3   r   r   r   available_keys[  s   zArchiveFormatter.available_keysc                 C      g }|   }| jD ]}|| q	| jD ](}|D ]}|| d| }|| jv r1|d| j|  7 }|| q|d q|rEJ t|d|S Nz- z: rz   r$  rG  r4  remove
KEY_GROUPSKEY_DESCRIPTIONSappendr   r}   r   helpr3   r5   r   r   r   r   r   r2  e     




zArchiveFormatter.keys_helpF)jsonr   c                C   s   || _ || _|| _d | _d | _d | _|| _|| _i }|| j	 t
||| _dd t |D | _t| jdddt| jdddt| jdddt| jddd| j| j| jd	| _t| j| j@ | _| jrmi | _| j| _d S || _d S )
Nc                 S      h | ]}|d  qS r   r   rC   fr   r   r   ry     rG   z,ArchiveFormatter.__init__.<locals>.<setcomp>r   T)rsr>  r8  F)r   r>  r8  r9  r<  r=  r?  )
repositoryr   r5   r   r   _archiverR  r   updater4  r   r   r   r   format_keysr   get_meta
get_ts_endget_cmdlineget_tamrE  r|   used_call_keys	item_dataformat_item_jsonr0  )r   r   rX  r   r5   rR  r   static_keysr   r   r   r   w  s2   	
zArchiveFormatter.__init__c                 C   s   t j| |tddd S )NT)r   	sort_keysr$  rR  dumpsr/  BorgJsonEncoderr.  r   r   r   rb    s   z!ArchiveFormatter.format_item_jsonc              
   C   s|   |j | _ |j| _i }|| j |t|j t|j |j t|j| |j| |jd | jD ]
}| j	|  ||< q1|S )N)r   r   r7  r   r;  r:  )
r   r   rZ  ra  r*   r   r   r   r`  rE  )r   Zarchive_infora  r5   r   r   r   r/    s   


zArchiveFormatter.get_item_datac                 C   sH   | j du s| j j| jkr!ddlm} || j| j| j| j| jd| _ | j S )z!lazy load / update loaded archiveNr	   Archiver   )	rY  r   r   ri  rX  r5   r   r   r   )r   ri  r   r   r   r     s   zArchiveFormatter.archivec                 C   s    | j j|d}|rt|S |S r   )r   metadatar0   r*   )r   r5   rW  r:   r   r   r   r\    s   zArchiveFormatter.get_metac                 C   s6   t t| jjdg }| jrt|S dt tj	|S )Ncmdliner   )
mapr*   r   rj  r0   rR  listr}   shlexquote)r   rk  r   r   r   r^    s   zArchiveFormatter.get_cmdlinec                 C   s   |  | jjS r.   )r   r   Zts_endr  r   r   r   r]    r   zArchiveFormatter.get_ts_endc                 C   s   | j jrdS dS )NZverifiednone)r   Ztam_verifiedr  r   r   r   r_       zArchiveFormatter.get_tamc                 C   s   t |S r.   )r   )r   r   r   r   r   r     r  zArchiveFormatter.format_timeN)r   r   r   rM  rL  classmethodrG  r2  r   rb  r/  r  r   r\  r^  r]  r_  r   r   r   r   r   r6  D  s<    
	

r6  c                   @   s   e Zd ZejdhddhZdddddd	d
dddddZddde	e
eddfZdZedd Zedd Zedd ZddddZd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2S )3ItemFormatterxxh64Z	shake_128Z	shake_256z9verbatim POSIX path, can contain any character except NULzJpath interpreted as text (might be missing non-text characters, see bpath)z/link target for links (identical to linktarget)zKprepends {source} with " -> " for soft links and " link to " for hard linkszcompressed sizezdeduplicated sizezdeduplicated compressed sizeznumber of chunks in this filez$number of unique chunks in this filezEXXH64 checksum of this file (note: this is NOT a cryptographic hash!)zPeither "healthy" (file ok) or "broken" (if file has all-zero replacement chunks))bpathr   sourceextracsizedsizedcsize
num_chunksunique_chunksrt  health)typer   uidgidr   r   r   ru  rv  
linktargetflags)rq   rx  ry  rz  r{  r|  )rp   ro   atimeisomtimeisoctimeisoatime)	archiveidrA  rw  )r}  )ry  rz  r|  c              	   C   sf   G dd d}ddl m} |dddddddd}| |d}g }||j  |||  |S )Nc                   @   s   e Zd Zd ZZdS )z1ItemFormatter.available_keys.<locals>.FakeArchiverz   N)r   r   r   fprr   r   r   r   r   FakeArchive  s    r  r	   )Itemr   rz   )r   r   r   r   rp   r  r  )r   r  rD  rE  r3   r/  )r   r  r  Z	fake_itemrF  r3   r   r   r   rG    s   
zItemFormatter.available_keysc                 C   rH  rI  rJ  rO  r   r   r   r2    rQ  zItemFormatter.keys_helpc                    s,   dd t  |D }t fdd|D S )Nc                 S   rS  rT  r   rU  r   r   r   ry     rG   z3ItemFormatter.format_needs_cache.<locals>.<setcomp>c                 3   s    | ]}| j v V  qd S r.   )KEYS_REQUIRING_CACHE)rC   r5   r   r   r   r_     s    z3ItemFormatter.format_needs_cache.<locals>.<genexpr>)r   r   any)r   r   r[  r   r  r   format_needs_cache  s   z ItemFormatter.format_needs_cacheF)
json_linesc                C   s&  ddl m} || _|| _|| _|j|jd}|| j | jr'i | _	| j
| _n|| _	t||| _dd t |D | _| j| jt| jdd t| jdd | jt| jd	d t| jd
t| jdt| jdt| jd
t| jdt| jdd| _| jD ]}t| j|| j|< q|t| j| j@ | _d S )Nr	   )StreamingXXH64)rA  r  c                 S   rS  rT  r   rU  r   r   r   ry     rG   z)ItemFormatter.__init__.<locals>.<setcomp>c                 S      | j S r.   )rq   chunkr   r   r   rJ         z(ItemFormatter.__init__.<locals>.<lambda>c                 S   r  r.   )rx  r  r   r   r   rJ     r  c                 S   r1  rH   r   r  r   r   r   rJ     s    rp   ro   r  )rq   rx  ry  rz  r{  r|  r  r  r  rp   ro   r  )Zalgorithms.checksumsr  rt  r   r  r   r  rZ  r4  ra  rb  r0  r   r   r   r   r[  calculate_sizecalculate_csizer   sum_unique_chunks_metadatacalculate_num_chunksformat_iso_timer   rE  hash_algorithms	hash_itemr|   r`  )r   r   r   r  r  rc  hash_functionr   r   r   r     s<   







zItemFormatter.__init__c                 C   s   t j| |tdd S )Nr  r$  re  r.  r   r   r   rb  *  r   zItemFormatter.format_item_jsonc                 C   s8  i }| | j t|j}|d }|dd}d}|r5t|}|dkr)d| }nd|dd   }d| }||d	< ||d
< |jpB|j|d< |j	pJ|j
|d< |j|d< |j
|d< t|j|d< | jrhd|v|d< n|j|d< ||d< d|v rwdnd|d< ||d< ||d< |dd|d< | jD ]}| j| |||< q|S )Nr   rv  rz   r   z -> %shr   z link to %sr~  r   r   r   r  r  r   Zchunks_healthyZhealthyru  rw  brokenr}  r  Zbsdflagsr  )rZ  ra  statfilemoder   r0   r*   r   r  r   r  r   r  r`  rE  )r   r   ra  r   Z	item_typerv  rw  r5   r   r   r   r/  -  s<   




zItemFormatter.get_item_datac                    sB   | j jj |dg }tdd |D t fdd|D S )au  
        sum unique chunks metadata, a unique chunk is a chunk which is referenced globally as often as it is in the
        item

        item: The item to sum its unique chunks' metadata
        metadata_func: A function that takes a parameter of type ChunkIndexEntry and returns a number, used to return
                       the metadata needed from the chunk
        chunksc                 s   s    | ]}|j V  qd S r.   r   rC   rl   r   r   r   r_   [  s    z;ItemFormatter.sum_unique_chunks_metadata.<locals>.<genexpr>c                 3   s.    | ]} |j  j|j  kr|V  qd S r.   )r   Zrefcountr  Zchunk_indexZchunks_countermetadata_funcr   r   r_   \  s   , )r   cacher  r0   r   sum)r   r  r   r  r   r  r   r  P  s   
	z(ItemFormatter.sum_unique_chunks_metadatac                 C   s   t |dg S )Nr  )rd   r0   r.  r   r   r   r  ^  rq  z"ItemFormatter.calculate_num_chunksc                 C      |j ddS )NF
compressedZget_sizer.  r   r   r   r  a     zItemFormatter.calculate_sizec                 C   r  )NTr  r  r.  r   r   r   r  e  r  zItemFormatter.calculate_csizec                 C   sd   d|vrdS |dkr|   }n
|| jv rt|}| jjdd |jD D ]}|| q&|	 S )Nr  rz   rt  c                 S   s   g | ]}|j qS r   r  r  r   r   r   rF   p  s    z+ItemFormatter.hash_item.<locals>.<listcomp>)
rt  r  hashlibnewr   ZpipelineZ
fetch_manyr  rZ  	hexdigest)r   r  r   hashr   r   r   r   r  i  s   


zItemFormatter.hash_itemc                 C   s   t t||p	|jS r.   )r   r   r0   rp   r   r5   r   r   r   r   r   t  r   zItemFormatter.format_timec                 C   s   |  || S r.   )r   	isoformatr  r   r   r   r  w  rq  zItemFormatter.format_iso_timeN)r   r   r   r  Zalgorithms_guaranteedunion
differencer  rM  rL   rM   rL  r  rr  rG  r2  r  r   rb  r/  r  r  r  r  r  r   r  r   r   r   r   rs    sL    
	


##rs  c                 C   sX   t | rdS t | rdS t | rdS t | rdS t | r#dS t | r*dS dS )NAr2   brl   r"   rV  ?)r  S_ISREGS_ISDIRS_ISBLKS_ISCHRS_ISLNKS_ISFIFO)r   r   r   r   file_status{  s   





r  Tc                 c   sT    | D ]$}|dur| |}|dur||}|r|sq|r$|dr$q|V  qdS )a  
    clean lines (usually read from a config file):

    1. strip whitespace (left and right), 2. remove empty lines, 3. remove comments.

    note: only "pure comment lines" are supported, no support for "trailing comments".

    :param lines: input line iterator (e.g. list or open text file) that gives unclean input lines
    :param lstrip: lstrip call arguments or False, if lstripping is not desired
    :param rstrip: rstrip call arguments or False, if rstripping is not desired
    :param remove_comments: remove comment lines (lines starting with "#")
    :param remove_empty: remove empty lines
    :return: yields processed lines
    F#N)r  r  r   )linesr  r  Zremove_emptyZremove_commentsliner   r   r   clean_lines  s   

r  c                 C   sr   ddl m} |dk }t|}|rt| } d}g }| D ]}|||7 }||kr( n|| q|r4|  d|S )a  
    Return a slice of *max_width* cells from *string*.

    Negative *max_width* means from the end of string.

    *max_width* is in units of character cells (or "columns").
    Latin characters are usually one cell wide, many CJK characters are two cells wide.
    r	   swidthr   rz   )r   r  r   r   rN  reverser}   )string	max_widthr  r  Zcurrent_swidthresult	characterr   r   r   swidth_slice  s   	
r  c                 C   sv   ddl m} |d}|| }|dk rdd||   S ||| k r3dt| |d | t| | d S | d||   S )z
    shorten a long string by adding ellipsis between it and return it, example:
    this_is_a_very_long_string -------> this_is..._string
    r	   r  z...   r   z{}...{})r   r  r   r  )rV   spacer  Zellipsis_widthZ	msg_widthr   r   r   ellipsis_truncate  s   r  c                       s   e Zd Z fddZ  ZS )rg  c                    s   ddl m} ddlm} ddlm} ddlm}m} t	||s$t	||r/t
|j|j dS t	||r8| S t	||rE|j| dS t	||rPd| iS tt|d	d r\| S t |S )
Nr	   )
Repository)RemoteRepositoryrh  )
LocalCache
AdHocCache)r   location)r   statsr  to_json)rX  r  Zremoter  r   ri  r  r  r  r/   r   r   Z	_locationr  infor   r  callablegetattrr  superr[   )r   or  r  ri  r  r  r   r   r   r[     s(   


zBorgJsonEncoder.default)r   r   r   r[   __classcell__r   r   r  r   rg    s    rg  )r  rw  c                C   sv   | j }|pi }|t | jd|jid t| jjt	j
d|d d< |jdr3| |d d< |r9||d	< |S )
Nr   )rX  
encryptionrB  rX  Zlast_modifiedzkey filer  Zkeyfiler  )r5   rZ  rg  r[   rX  ZARG_NAMEr   Zlast_timestampr(   r   r   NAMEr   Zfind_key)r   r  rw  r5   r   r   r   r   basic_json_data  s   r  c                 C   s   t j| ddtdS )zDump using BorgJSONEncoder.Tr]   )rd  indentr   )rR  rf  rg  r   r   r   r   	json_dump  r+   r  c                 C   s   t t|  d S r.   )printr  r  r   r   r   
json_print  rq  r  c                    s0   dd  fdd fdd  | S )Nc                 S   s8   |  dsz|  } | W S  ty   Y nw dt|  S )N   )r   r   UnicodeDecodeErrorr   )r:   r   r   r   decode_bytes  s   
z'prepare_dump_dict.<locals>.decode_bytesc                    s`   g }| D ])}t |tr |}nt |tst |tr|}n	t |tr(|}|| q|S r.   )r/   r{   rL   rm  r1   rN  )rI   resr:   r   r  decode_tupler   r   r    s   



z'prepare_dump_dict.<locals>.decode_tuplec                    st   t  }|  D ]0\}}t|tr |}nt|ttfr!|}n	t|tr*|}t|tr3| }|||< q|S r.   )r   rN   r/   r{   rL   rm  r1   r   )r2   r  r5   r:   r  r   r   r      s   





z!prepare_dump_dict.<locals>.decoder   )r2   r   r  r   prepare_dump_dict  s   r  )r   r   )r(   )r	   FF)r   NNrz   r	   F)r   rz   r	   F)NN)NNTT)Vr8   r  rR  r   os.pathr   rn  socketr  r   binasciir   collectionsr   r   r   r   	functoolsr   r  r   rT   r
   r#   r   fsr   r;  r   r   r   r   r   rz   r   r   r   r   	constantsZplatformflagsr   r   r$   r'   r*   r-   r6   r;   rS   rk   r   r   r   r   r   r   r   Z
PrefixSpecZGlobSpecZCommentSpecr   r   r7   r   r   r   r   r   r   r   r   r!  r"  r#  r6  rs  r  r  r  r  JSONEncoderrg  r  r  r  r  r   r   r   r   <module>   s    



)





 
X	  7
