o
    -wi47                     @   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mZmZmZ d dlmZ eeZddd edD d	 Zd
eddfddZdedeeddf fddZd
edefddZdedeejddf fddZG dd dZ G dd de Z!dededefddZ"e j#	d4dededed edeeddf f
d!d"Z$dededefd#d$Z%d%ed&eddfd'd(Z&d%ed&eddfd)d*Z'd5d%ed&ed,e(ddfd-d.Z)dedee fd/d0Z*d5ded1e(defd2d3Z+dS )6    N)Path)IOAnyBinaryIO	GeneratorOptional)StrPath c                 c   s    | ]}t |V  qd S N)chr).0i r   U/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/wandb/sdk/lib/filesystem.py	<genexpr>   s    r       z:"*<>?|dir_namereturnc              
   C   sd   z
t j| dd W dS  ty } zt| d|d}~w ty1 } zt| d|d}~ww )zCreate `dir_name` and any parent directories if they don't exist.

    Raises:
        FileExistsError: if `dir_name` exists and is not a directory.
        PermissionError: if `dir_name` is not writable.
    Texist_okz exists and is not a directoryNz is not writable)osmakedirsFileExistsErrorPermissionError)r   er   r   r   mkdir_exists_ok   s   r   pathc                 c   s\    t | } tj| \}}tj||V  tD ]}||v r+||d}tj||V  qdS )zYield variations of `path` that may exist on the filesystem.

    Return a sequence of paths that should be checked in order for existence or
    create-ability. Essentially, keep replacing "suspect" characters until we run out.
    -N)strr   r   
splitdrivejoinPROBLEMATIC_PATH_CHARSreplace)r   roottailcharr   r   r   path_fallbacks%   s   r&   c                 C   s   t | D ]P}z,tj|dd t|t| kr"td| d|  d t| tr.t|W   S |W   S  ttfy=   Y q t	yT } z|j
dkrJ W Y d}~qd}~ww t	d|  d)	zCreate `dir_name`, removing invalid path characters if necessary.

    Returns:
        The path to the created directory, which may not be the original path.
    Tr   z
Creating 'z' instead of ''   NzUnable to create directory ')r&   r   r   r   loggerwarning
isinstance
ValueErrorNotADirectoryErrorOSErrorerrno)r   new_namer   r   r   r   mkdir_allow_fallback4   s   "
r1   c                 c   sF    t j| s	dS t | D ]}| rt|jE dH  q|V  qdS )zEYield a directory entry for each file under a given path (recursive).N)r   r   isdirscandiris_dirfiles_in)r   entryr   r   r   r5   I   s   r5   c                   @   s6   e Zd ZdZdeddfddZdddZdd	d
ZdS )WriteSerializingFilez1Wrapper for a file object that serializes writes.fr   Nc                 C   s   t  | _|| _d S r
   )	threadingLocklockr8   selfr8   r   r   r   __init__W   s   

zWriteSerializingFile.__init__c                 O   sD   | j   z| jj|i | | j  W | j   d S | j   w r
   )r;   acquirer8   writeflushrelease)r=   argskargsr   r   r   r@   [   s
   
zWriteSerializingFile.writec                 C   s2   | j   z| j  W | j   d S | j   w r
   )r;   r?   r8   closerB   r=   r   r   r   rE   c   s   
zWriteSerializingFile.closer   N)__name__
__module____qualname____doc__r   r>   r@   rE   r   r   r   r   r7   T   s
    
r7   c                       sB   e Zd Zdeddf fddZd
 fddZd
 fdd	Z  ZS )CRDedupedFiler8   r   Nc                    s   t  j|d d| _d S )N)r8       )superr>   _buffr<   	__class__r   r   r>   l   s   
zCRDedupedFile.__init__c                    s   t d|}g }|D ]%}|d d dkr!|r|  n| jr!d| _|dd }|r/|| q
| jr:|d| j |rA| | _t d|d  d S )Ns   
|
      rM   r      
)	resplitpoprO   appendinsertrN   r@   r    )r=   datalinesretlinerP   r   r   r@   p   s"   


zCRDedupedFile.writec                    s"   | j r
t | j  t   d S r
   )rO   rN   r@   rE   rF   rP   r   r   rE      s   zCRDedupedFile.closerG   )rH   rI   rJ   r   r>   r@   rE   __classcell__r   r   rP   r   rL   k   s    rL   source_pathtarget_pathc                 C   s   t |}t|dd}tj| pt| jt|jk}t| j}|rntj|\}}tj	t
||}zt| | W n) tyg   zt|| t| | W n tyd } ztd|d}~ww Y nw t|| ||S )a  Copy source_path to target_path, unless it already exists with the same mtime.

    We liberally add write permissions to deal with the case of multiple users needing
    to share the same cache or run directory.

    Args:
        source_path: The path to the file to copy.
        target_path: The path to copy the file to.

    Returns:
        The path to the copied file (which may be different from target_path).
    T)warnz%Unable to overwrite '{target_path!s}'N)typesystem_preferred_pathr   r   isfilestatst_mtimest_moderW   r    r1   shutilcopy2r   chmod)r`   ra   return_type	need_copypermissions_plus_writer   	file_namer   r   r   r   copy_or_overwrite_changed   s.   
rp   rmoderC   kwargsc              	   o   s   t |  } | jjddd d|v r|  rt| dd|v rHd|vrH| j|g|R i |}|V  W d   dS 1 sAw   Y  dS tj| jdi}t || j	 }d|v s_d	|v ri|  rit
| | |j|g|R i |}|V  |  t|  W d   n1 sw   Y  d|v rt||  t| n||  W d   dS W d   dS 1 sw   Y  dS )
a/  Open a file, ensuring any changes only apply atomically after close.

    This context manager ensures that even unsuccessful writes will not leave a "dirty"
    file or overwrite good data, and that all temp data is cleaned up.

    The semantics and behavior are intended to be nearly identical to the built-in
    open() function. Differences:
        - It creates any parent directories that don't exist, rather than raising.
        - In 'x' mode, it checks at the beginning AND end of the write and fails if the
            file exists either time.
    Tparentsr   x already existsrq   +Ndira)r   resolveparentmkdirexistsr   opentempfileTemporaryDirectorynameri   rj   rA   r   fsyncfilenolinkunlinkr"   )r   rr   rC   rs   r8   tmp_dirtmp_pathr   r   r   	safe_open   s8   
"r   c                 C   s~   t | }|jjddd tj|jd }t |t | j d}t	| | |
| W d   |S 1 s8w   Y  |S )a  Copy a file atomically.

    Copying is not usually atomic, and on operating systems that allow multiple
    writers to the same file, the result can get corrupted. If two writers copy
    to the same file, the contents can become interleaved.

    We mitigate the issue somewhat by copying to a temporary file first and
    then renaming. Renaming is atomic: if process 1 renames file A to X and
    process 2 renames file B to X, then X will either contain the contents
    of A or the contents of B, not some mixture of both.
    Trt   ry   z.tmpN)r   r|   r}   r~   r   r   r   with_suffixri   rj   r"   )r`   ra   output_pathr   r   r   r   r   	safe_copy   s   
r   existing_pathnew_pathc              	   C   s   ddl }d}t| d1}t|d}|| ||  W d   n1 s'w   Y  W d   dS W d   dS 1 s?w   Y  dS )z;Create a reflink to `existing_path` at `new_path` on Linux.r   Ni	@rbzwb+)fcntlr   ioctlr   )r   r   r   FICLONEt_fl_fr   r   r   _reflink_linux   s
   Pr   c              
   C   s   z	t jddd}W n( ttfy1 } zt  tjkr t|ts  t jddd}W Y d }~nd }~ww z|j}W n t	yD   ttj
dw t jt jt jf|_t j|_|t| t|t drnt  }t|t|| d S )Nz
libc.dylibT)	use_errnoz/usr/lib/libSystem.dylibz+'clonefile' is not available on this systemr   )ctypesCDLLFileNotFoundErrorr.   	get_errnor/   ENOENTr+   	clonefileAttributeErrorENOTSUPc_char_pc_intargtypesrestyper   fsencodestrerror)r   r   clibr   r   errr   r   r   _reflink_macos  s&   
r   F	overwritec              
   C   s  t  dkr	t}nt  dkrt}nttjdt   t| }t|  } |	 rC|s6t
| dtd| d |  |jjddd z|| | W dS  ty } zfd	|  d
| d}|jtjtjfv rutd| ||jtjkrtd| ||jtjkrtd| ||jtjkrtd| ||jtjtjfv rttjd| ||jtjkrtd| | d}~ww )a9  Create a reflink to `existing_path` at `new_path`.

    A reflink (reflective link) is a copy-on-write reference to a file. Once linked, the
    file and link are both "real" files (not symbolic or hard links) and each can be
    modified independently without affecting the other; however, they share the same
    underlying data blocks on disk so until one is modified they are "zero-cost" copies.

    Reflinks have all the functionality of copies, so we should use them wherever they
    are supported if we would otherwise copy a file. (This is not particularly radical--
    GNU `cp` defaults to `reflink=auto`, using it whenever available) However, support
    for them is limited to a small number of filesystems. They should work on:
    - Linux with a Btrfs or XFS filesystem (NOT ext4)
    - macOS 10.13 or later with an APFS filesystem (called clone files)

    Reflinks are also supported on Solaris and Windows with ReFSv2, but we haven't
    implemented support for them.

    Like hard links, a reflink can only be created on the same filesystem as the target.
    LinuxDarwinzreflinks are not supported on rw   zOverwriting existing file .Trt   zfailed to create reflink from z to zInsufficient permissions; zFile not found; z Cannot link across filesystems; zCannot reflink a directory; z&Filesystem does not support reflinks; zCannot link file ranges; N)platformsystemr   r   r.   r/   r   r   r|   r   r   r)   r*   r   r}   r~   EPERMEACCESr   r   r   EXDEVr,   EISDIRIsADirectoryError
EOPNOTSUPPEINVAL)r   r   r   link_fnr   base_msgr   r   r   reflink  sN   r   c                 C   s<   t | D ]}tj|rt| trt|  S |  S qdS )a  Look for variations of `path` and return the first found.

    This exists to support former behavior around system-dependent paths; we used to use
    ':' in Artifact paths unless we were on Windows, but this has issues when e.g. a
    Linux machine is accessing an NTFS filesystem; we might need to look for the
    alternate path. This checks all the possible directories we would consider creating.
    N)r&   r   r   r   r+   r   )r   destr   r   r   check_existsY  s
   r   rb   c                 C   sd   t  dkr| S tj| \}}|rd|v rtd| d ||dd }t| t	r0t	|S |S )zReplace ':' with '-' in paths on Windows.

    Args:
        path: The path to convert.
        warn: Whether to warn if ':' is replaced.
    Windows:zReplacing ':' in z	 with '-'r   )
r   r   r   r   r   r)   r*   r"   r+   r   )r   rb   headr$   r   r   r   r   rd   g  s   rd   )rq   )F),
contextlibr   r/   loggingr   r   rV   ri   r   r9   pathlibr   typingr   r   r   r   r   wandb.sdk.lib.pathsr   	getLoggerrH   r)   r    ranger!   r   r   r&   r1   DirEntryr5   r7   rL   rp   contextmanagerr   r   r   r   boolr   r   rd   r   r   r   r   <module>   sR    
*2	>