o
                         @   sj  d Z ddlmZ ddlmZ ddlm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ZddlZddlZddlmZ ddlmZ ddlmZ dd	lmZ ddlZdd
lmZ dZze W n eyw   dZY nw G dd deZG dd deZ dd Z!d|ddZ"dd Z#g dZ$dd Z%dd f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-d.Z.d/d0 Z/d1d2 Z0		d~d3d4Z1d5d6 Z2d7d8 Z3G d9d: d:e4Z5G d;d< d<e4Z6G d=d> d>e4Z7G d?d@ d@eZ8G dAdB dBe8Z9G dCdD dDeZ:G dEdF dFe4Z;G dGdH dHe4Z<G dIdJ dJe4Z=ej>dKdL Z?dMdN Z@dOdP ZA	ddQdRZBd}dSdTZC				ddUdVZDdWdX ZEdYdZ ZF	[		[		dd\d]ZG	[		[	dd^d_ZHd`da ZIdbdc ZJddde ZK					ddfdgZLG dhdi diejMZNdeNjOddfdjdkZP					ddldmZQdndo ZRdpdq ZSdrds ZTdtdu ZUddvdwZVdxdy ZWdzd{ ZXdS )zCSome general file utilities used that can be used by the Cloud SDK.    )absolute_import)division)unicode_literalsN)
exceptionsencoding)	platforms)retry)range
   c                   @      e Zd ZdZdS )Errorz)Base exception for the file_utils module.N__name__
__module____qualname____doc__ r   r   ;/tmp/google-cloud-sdk/lib/googlecloudsdk/core/util/files.pyr   6       r   c                   @   r   )MissingFileErrorz%Error for when a file does not exist.Nr   r   r   r   r   r   ;   r   r   c                 C   s   t | g }t | D ]`}t|}t j| |}t j||}zt j|r.t|| nt	
|| W q t	jyP } z||jd  W Y d}~qd}~w tyl } z|||t|f W Y d}~qd}~ww |rtt	|dS )au  Copies a directory recursively, without copying file stat info.

  More specifically, behaves like `cp -R` rather than `cp -Rp`, which means that
  the destination directory and its contents will be *writable* and *deletable*.

  (Yes, an omnipotent being can shutil.copytree a directory so read-only that
  they cannot delete it. But they cannot do that with this function.)

  Adapted from shutil.copytree.

  Args:
    src: str, the path to the source directory
    dst: str, the path to the destination directory. Must not already exist and
      be writable.

  Raises:
    shutil.Error: if copying failed for any reason.
  r   N)osmakedirslistdirencoding_utilDecodepathjoinisdirCopyTreeshutilcopy2r   extendargsEnvironmentErrorappendsix	text_type)srcdsterrorsnamesrcnamedstnameerrwhyr   r   r   r   @   s*   

"
r     Fc              
   C   s   |rt j t jjkrt | } z
tj| |d W dS  ty` } z:d| }|j	t	j
kr4tj| r4n!|j	t	j
krFtj| rFt|d |j	t	jkrTt|d d  W Y d}~dS d}~ww )a  Creates the given directory and its parents and does not fail if it exists.

  Args:
    path: str, The path of the directory to create.
    mode: int, The permissions to give the created directories. 0777 is the
      default mode for os.makedirs(), allowing reading, writing, and listing by
      all users on the machine.
    convert_invalid_windows_characters: bool, Convert invalid Windows path
      characters with an 'unsupported' symbol rather than trigger an OSError on
      Windows (e.g. "file|.txt" -> "file$.txt").

  Raises:
    Error: if the operation fails and we can provide extra information.
    OSError: if the operation fails.
  modez"Could not create directory [{0}]: z!A file exists at that location.

zPermission denied.

zIPlease verify that you have permissions to write to the parent directory.N)r   OperatingSystemCurrentWINDOWSMakePathWindowsCompatibler   r   OSErrorformaterrnoEEXISTr   r   isfiler   EACCES)r   r2   "convert_invalid_windows_charactersexbase_msgr   r   r   MakeDiri   s*   

r@   c                 C   s*   ddt |    }td| t| dS )zSleeps for a period of time based on the retry count.

  Args:
    retries_left: int, The number of retries remaining.  Should be in the range
      of NUM_RETRIES - 1 to 0.
  g?   zWaiting for retry: [%s]N)NUM_RETRIESloggingdebugtimesleep)retries_lefttime_to_waitr   r   r   _WaitForRetry   s   rI   )          c                 C   sB   | t jks| t jks| t jksdS tsdS |d }t|ddtv S )aZ  Matches specific error types that should be retried.

  This will retry the following errors:
    WindowsError(5, 'Access is denied'), When trying to delete a readonly file
    WindowsError(32, 'The process cannot access the file because it is being '
      'used by another process'), When a file is in use.
    WindowsError(145, 'The directory is not empty'), When a directory cannot be
      deleted.

  Args:
    func: function, The function that failed.
    exc_info: sys.exc_info(), The current exception state.

  Returns:
    True if the error can be retried or false if we should just fail.
  F   winerrorN)r   removermdirunlinkWindowsErrorgetattrRETRY_ERROR_CODES)funcexc_infoer   r   r   _ShouldRetryOperation   s   rX   c                 C      dS NTr   )rU   rV   r   r   r   <lambda>       r[   c                 C   sn   t }|dkr5||| r5td||| | |d8 }zt| ||  W dS    t } Y |dkr5||| sdS )a  Attempts to retry the failed file operation.

  Args:
    exc_info: sys.exc_info(), The current exception state.
    func: function, The function that failed.
    args: (str, ...), The tuple of args that should be passed to func when
      retrying.
    retry_test_function: The function to call to determine if a retry should be
      attempted.  Takes the function that is being retried as well as the
      current exc_info.

  Returns:
    True if the operation eventually succeeded or False if it continued to fail
    for all retries.
  r   z;Retrying file system operation: %s, %s, %s, retries_left=%srM   TF)rB   rC   rD   rI   sysrV   )rV   rU   r#   retry_test_functionrG   r   r   r   _RetryOperation   s   
r_   c                 C   s   t d| || t|tst|||jf}tr/t|d tr/t|d dddkr/t	
|tj t|| |ftsDtj|d |d d dS dS )	zA function to pass as the onerror arg to rmdir for handling errors.

  Args:
    func: function, The function that failed.
    failed_path: str, The path of the file the error occurred on.
    exc_info: sys.exc_info(), The current exception state.
  z&Handling file system error: %s, %s, %sr   rM   rN   NrJ   rA   )tb)rC   rD   
isinstancetupletype__traceback__rR   
issubclassrS   r   chmodstatS_IWUSRr_   rX   r   reraise)rU   failed_pathrV   r   r   r   _HandleRemoveError   s   

rk   c                 C   s   t | } tjdd dk rtj| td ntj| td t}tj	
| rC|dkrGtd|  |d8 }t| tj	
| rE|dks)dS dS dS dS )	zCalls shutil.rmtree() with error handling to fix Windows problems.

  It also ensures that the top level directory deletion is actually reflected
  in the file system before this returns.

  Args:
    path: str, The path to remove.
  NrA   )      )onerror)onexcr   z&Waiting for directory to disappear: %srM   )r&   r'   r]   version_infor    rmtreerk   rB   r   r   r   rC   rD   rI   )r   rG   r   r   r   RmTree   s   
$rr   c                 C   sV   t j| } t j|}| t jjs| t jj7 } |t jjs&|t jj7 }|| S N)r   r   abspathendswithsep
startswith)r(   r)   r   r   r   
_DestInSrc  s   
rx   c              
   C   s   t j| std| t j|rtd|t| |r'td| |z)td| | z
t 	| | W W dS  t
yP   tt t j	| |fsL Y W dS w  t
yu } ztd| tj| |dd t|  W Y d}~dS d}~ww )	a  Recursively moves a directory to another location.

  This code is mostly copied from shutil.move(), but has been scoped down to
  specifically handle only directories.  The src must be a directory, and
  the dst must not exist.  It uses functions from this module to be resilient
  against spurious file system errors in Windows.  It will try to do an
  os.rename() of the directory.  If that fails, the tree will be copied to the
  new location and then deleted from the old location.

  Args:
    src: str, The directory path to move.
    dst: str, The path to move the directory to.

  Raises:
    Error: If the src or dst directories are not valid.
  z%Source path '{0}' must be a directoryz%Destination path '{0}' already existsz0Cannot move a directory '{0}' into itself '{1}'.z)Attempting to move directory [%s] to [%s]z4Directory rename failed.  Falling back to copy. [%s]T)symlinksN)r   r   r   r   r8   existsrx   rC   rD   renamer7   r_   r]   rV   r    copytreerr   )r(   r)   rW   r   r   r   MoveDir  s.   
r}   c                 C   s\   d}t tj| }||kr,tj||}tj|r|S |}tj|\}}||ksdS )a  Searches directories upwards until it finds one with the given contents.

  This can be used to find the directory above you that contains the given
  entry.  It is useful for things like finding the workspace root you are under
  that contains a configuration directory.

  Args:
    starting_dir_path: str, The path of the directory to start searching
      upwards from.
    directory_entry_name: str, The name of the directory that must be present
      in order to return the current directory.

  Returns:
    str, The full path to the directory above the starting dir that contains the
    given entry, or None if the root of the file system was hit without finding
    it.
  N)r   r   r   r   realpathr   r   split)starting_dir_pathdirectory_entry_name	prev_pathr   
search_dir_r   r   r   FindDirectoryContaining@  s   r   c                 C   s   t j| std| tt j|}tt j| } z	t j|| }W n
 ty2   Y dS w |	dt jj
  o@|dkS )a  Returns whether ancestor_directory is an ancestor of path.

  Args:
    ancestor_directory: str, path to the directory that is the potential
      ancestor of path
    path: str, path to the file/directory that is a potential descendant of
      ancestor_directory

  Returns:
    bool, whether path has ancestor_directory as an ancestor.

  Raises:
    ValueError: if the given ancestor_directory is not, in fact, a directory.
  z[{0}] is not a directory.Fz..)r   r   r   
ValueErrorr8   r   r   r~   relpathrw   rv   )ancestor_directoryr   relr   r   r   IsDirAncestorOf]  s   
r   c                   C   s   t tjdS )z5Returns properly encoded system PATH variable string.PATH)r   GetEncodedValuer   environr   r   r   r   _GetSystemPath|     r   c                 C   sT   |s	t  }|s	g S |tj}g }|D ]}tj|| }tj|r'|| q|S )a  Tries to find all 'executable' in the directories listed in the PATH.

  This is mostly copied from distutils.spawn.find_executable() but with a
  few differences.  It does not check the current directory for the
  executable.  We only want to find things that are actually on the path, not
  based on what the CWD is.  It also returns a list of all matching
  executables.  If there are multiple versions of an executable on the path
  it will return all of them at once.

  Args:
    executable: The name of the executable to find
    path: A path to search.  If none, the system PATH will be used.

  Returns:
    A list of full paths to matching executables or an empty list if none
    are found.
  )r   r   r   pathsepr   r   r;   r%   )
executabler   pathsmatchingpfr   r   r   SearchForExecutableOnPath  s   
r   c                 C   s   t |tjrtd||D ]0}|tjD ]'}|d}tj	
tj	|| | }tj	|r>t|tjr>|    S qqdS )a}  Internal function to a find an executable.

  Args:
    executable: The name of the executable to find.
    path: A list of directories to search separated by 'os.pathsep'.
    pathext: An iterable of file name extensions to use.

  Returns:
    str, the path to a file on `path` with name `executable` + `p` for
      `p` in `pathext`.

  Raises:
    ValueError: invalid input.
  zr_FindExecutableOnPath(..., pathext='{0}') failed because pathext must be an iterable of strings, but got a string."N)ra   r&   string_typesr   r8   r   r   r   stripr   normpathr   r;   accessX_OK)r   r   pathextext	directoryfullr   r   r   _FindExecutableOnPath  s   
r   c                 C   s   | t jjkrdS dS )N)z.exez.cmdz.batz.comz.ps1) z.sh)r   r3   r5   )platformr   r   r   _PlatformExecutableExtensions  s   r   c                 C   s   |st j| d rtd| t j| rtd| |du r,t }|du r+dS n|}|dur4|nttj	
 }t| ||S )a$  Searches for `executable` in the directories listed in `path` or $PATH.

  Executable must not contain a directory or an extension.

  Args:
    executable: The name of the executable to find.
    path: A list of directories to search separated by 'os.pathsep'.  If None
      then the system PATH is used.
    pathext: An iterable of file name extensions to use.  If None then
      platform specific extensions are used.
    allow_extensions: A boolean flag indicating whether extensions in the
      executable are allowed.

  Returns:
    The path of 'executable' (possibly with a platform-specific extension) if
    found and executable, None if not found.

  Raises:
    ValueError: if executable has a path or an extension, and extensions are
      not allowed, or if there's an internal error.
  rM   zWFindExecutableOnPath({0},...) failed because first argument must not have an extension.zQFindExecutableOnPath({0},...) failed because first argument must not have a path.N)r   r   splitextr   r8   dirnamer   r   r   r3   r4   r   )r   r   r   allow_extensionseffective_patheffective_pathextr   r   r   FindExecutableOnPath  s,   r   c                 C   sT  t j| stdj| dt j| d}t |t jr#t |t js%dS t j| djt 	 d}t
dD ]q}zt |t jt jB d}t | W n, tyv } z |jtjkr`W Y d	}~ dS |jtjtjfv rqtdj| d d	}~ww z	t | W  d
S  ty } z|jtjkrW Y d	}~ dS |jtjkr W Y d	}~q6d	}~ww dS )a7  Determines if the current user is able to modify the contents of the dir.

  Args:
    directory: str, The full path of the directory to check.

  Raises:
    ValueError: If the given directory path is not a valid directory.

  Returns:
    True if the current user has missing write and execute permissions.
  z+The given path [{path}] is not a directory.r   .Fz.HasWriteAccessInDir{pid})pidr   i  NT)r   r   r   r   r8   r   r   r   W_OKgetpidr
   openO_RDWRO_CREATcloser7   r9   r<   ENOTDIRENOENTrO   )r   r   r   fdrW   r   r   r   HasWriteAccessInDir  sH   
	


r   c                   C   s   t t S )z%Returns os.getcwd() properly decoded.)r   r   r   getcwdr   r   r   r   GetCWD8  r   r   c                   @   s>   e Zd ZdZdddZedd Zdd Zd	d
 Zdd Z	dS )TemporaryDirectoryzA class to easily create and dispose of temporary directories.

  Securely creates a directory for temporary use.  This class can be used with
  a context manager (the with statement) to ensure cleanup in exceptional
  situations.
  Fc                 C   s0   t  | _d | _|rt | _t| j d S d S rs   )tempfilemkdtemp_TemporaryDirectory__temp_dir_curdirr   r   chdir)self	change_tor   r   r   __init__E  s   
zTemporaryDirectory.__init__c                 C      | j S rs   )r   r   r   r   r   r   L  s   zTemporaryDirectory.pathc                 C   r   rs   r   r   r   r   r   	__enter__P  s   zTemporaryDirectory.__enter__c                 C   s6   z|    W dS    tj|||gt R   Y dS )NF)Closer   RaiseWithContextr]   rV   )r   prev_exc_typeprev_exc_valprev_exc_tracer   r   r   __exit__S  s   

zTemporaryDirectory.__exit__c                 C   s4   | j d urt| j  | jrt| j d | _dS dS )NTF)r   r   r   r   rr   r   r   r   r   r   r   \  s   

zTemporaryDirectory.CloseNF)
r   r   r   r   r   propertyr   r   r   r   r   r   r   r   r   =  s    

	r   c                   @   sj   e Zd ZdZejfddZdd Zdd Zdd	 Z	d
d Z
dd ZeejfddZeejfddZdS )Checksumz@Consistently handles calculating checksums across the Cloud SDK.c                 C   s   | | _ t | _dS )zCreates a new Checksum.N)_Checksum__hashset_Checksum__files)r   	algorithmr   r   r   r   i  s   zChecksum.__init__c                 C   s   | j t| | S )zAdds the given contents to the checksum.

    Args:
      contents: str or bytes, The contents to add.

    Returns:
      self, For method chaining.
    )r   updater&   ensure_binary)r   contentsr   r   r   AddContentsn  s   	zChecksum.AddContentsc                 C   sN   t |}	 |d}|sn| j| qW d   | S 1 s w   Y  | S )zAdds the contents of the given file to the checksum.

    Args:
      file_path: str, The file path of the contents to add.

    Returns:
      self, For method chaining.
    Ti   N)BinaryFileReaderreadr   r   )r   	file_pathfpchunkr   r   r   AddFileContentsz  s   
	

zChecksum.AddFileContentsc           	      C   s   t |}t|D ]s\}}}|jtjjd |jtjjd |D ])}tj||}tj|rJtj	||}| j
| | | | t| q!|D ]/}tj||}tj	||}| j
| | | tj|rw| t| qM| | qMq
| S )a  Adds all files under the given directory to the checksum.

    This adds both the contents of the files as well as their names and
    locations to the checksum.  If the checksums of two directories are equal
    this means they have exactly the same files, and contents.

    Args:
      dir_path: str, The directory path to add all files from.

    Returns:
      self, For method chaining.
    )key)r&   r'   r   walksortr   normcaser   islinkr   r   addr   readlinkr   )	r   dir_pathrootdirsfilesdr   r   r   r   r   r   AddDirectory  s,   


	zChecksum.AddDirectoryc                 C   s
   | j  S )z~Gets the hex digest for all content added to this checksum.

    Returns:
      str, The checksum digest as a hex string.
    )r   	hexdigestr   r   r   r   	HexDigest  s   
zChecksum.HexDigestc                 C   r   )zGets the list of all files that were discovered when adding a directory.

    Returns:
      {str}, The relative paths of all files that were found when traversing the
      directory tree.
    )r   r   r   r   r   Files  s   zChecksum.Filesc                 C   s   t |d| S )zCreates a Checksum containing one file.

    Args:
      input_path: str, The file path of the contents to add.
      algorithm: a hashing algorithm method, a la hashlib.algorithms

    Returns:
      Checksum, The checksum containing the file.
    r   )r   r   
input_pathr   r   r   r   FromSingleFile  s   zChecksum.FromSingleFilec                 C   s   t j| |d S )a   Gets the hex digest of a single file.

    Args:
      input_path: str, The file path of the contents to add.
      algorithm: a hashing algorithm method, ala hashlib.algorithms

    Returns:
      str, The checksum digest of the file as a hex string.
    r   )r   r   r   r   r   r   r   HashSingleFile  s   zChecksum.HashSingleFileN)r   r   r   r   hashlibsha256r   r   r   r   r   r   staticmethodr   r   r   r   r   r   r   f  s    )	r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ChDirzNDo some things from a certain directory, and reset the directory afterward.
  c                 C   s
   || _ d S rs   )_ChDir__dir)r   r   r   r   r   r     s   
zChDir.__init__c                 C   s   t  | _t| j | jS rs   )r   _ChDir__original_dirr   r   r   r   r   r   r   r     s   zChDir.__enter__c                 C   s   t | j d S rs   )r   r   r   )r   typvaluer`   r   r   r   r     s   zChDir.__exit__N)r   r   r   r   r   r   r   r   r   r   r   r     s
    r   c                   @      e Zd ZdS )FileLockLockingErrorNr   r   r   r   r   r   r   r         r   c                   @   r   )FileLockTimeoutErrorzA case of FileLockLockingError.Nr   r   r   r   r   r     r   r   c                   @   r   )FileLockUnlockingErrorNr   r   r   r   r   r     r   r   c                   @   s:   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdS )FileLockzA file lock for interprocess (not interthread) mutual exclusion.

  At most one FileLock instance may be locked at a time for a given local file
  path. FileLock instances may be used as context objects.
  Nc                 C   sB   || _ || _d| _d| _tj tjjkrt | _	dS t
 | _	dS )a)  Constructs the FileLock.

    Args:
      path: str, the path to the file to lock. The directory containing the
        file must already exist when Lock() is called.
      timeout_secs: int, seconds Lock() may wait for the lock to become
        available. If None, Lock() may block forever.
    NF)_path_timeout_secs_file_lockedr   r3   r4   r5   _WindowsLocking_impl_PosixLocking)r   r   timeout_secsr   r   r   r     s   	zFileLock.__init__c              
   C   s   | j rdS zt| j| _W n ty } zt|d}~ww d}| jdur*d| j }tj|d}z|j	| j
j| j gdd W n tjy] } z| j  d| _td| jd}~ww d| _ dS )aT  Opens and locks the file. A no-op if this FileLock is already locked.

    The lock file is created if it does not already exist.

    Raises:
      FileLockLockingError: if the file could not be opened (or created when
        necessary).
      FileLockTimeoutError: if the file could not be locked before the timeout
        elapsed.
    Ni  )max_wait_msd   )r#   sleep_msz#Timed-out waiting to lock file: {0}T)r  
FileWriterr  r  r   r   r  r	   RetryerRetryOnExceptionr  TryLockfilenoRetryExceptionr   r   r8   )r   rW   r	  rr   r   r   Lock  s2   





zFileLock.Lockc              
   C   sx   | j sdS z*z| j| j  W n ty! } zt|d}~ww W | j  d| _d| _ dS | j  d| _d| _ w )zUnlocks and closes the file.

    A no-op if this object is not locked.

    Raises:
      FileLockUnlockingError: if a problem was encountered when unlocking the
        file. There is no need to retry.
    NF)r  r  Unlockr  r  IOErrorr   r   )r   rW   r   r   r   r  8  s   	


zFileLock.Unlockc                 C   s   |    | S )z'Locks and returns this FileLock object.)r  r   r   r   r   r   M  s   zFileLock.__enter__c              
   C   sF   z|    W dS  ty" } ztd| j| W Y d}~dS d}~ww )z(Unlocks, logging any errors encountered.z'Encountered error unlocking file %s: %sNF)r  r   rC   rD   r  )r   exc_typeexc_valexc_tbrW   r   r   r   r   R  s   
zFileLock.__exit__rs   )	r   r   r   r   r   r  r  r   r   r   r   r   r   r     s    
"r   c                   @       e Zd ZdZdd Zdd ZdS )r  z6Exclusive, non-blocking file locking on POSIX systems.c                 C   s    ddl }|||j|jB  dS )Raises IOError on failure.r   N)fcntlflockLOCK_EXLOCK_NBr   r   r  r   r   r   r  a  s   z_PosixLocking.TryLockc                 C   s   dd l }|||j d S )Nr   )r  r  LOCK_UNr  r   r   r   r  h  s   z_PosixLocking.UnlockNr   r   r   r   r  r  r   r   r   r   r  ^      r  c                   @   r  )r  z0Exclusive, non-blocking file locking on Windows.c                 C   s   ddl }|||jd dS )r  r   NrM   )msvcrtlockingLK_NBLCKr   r   r#  r   r   r   r  q  s   z_WindowsLocking.TryLockc                 C   s   dd l }|||jd d S )Nr   rM   )r#  r$  LK_UNLCKr&  r   r   r   r  x  s   z_WindowsLocking.UnlockNr!  r   r   r   r   r  n  r"  r  c              
   c   s    z|   }W n ttjfy   dV  Y dS w tj r<ddl}z||t	j
}dV  W ||| dS ||| w dV  dS )a  Context manager to temporarily swap a file to binary mode on Windows.

  On exit, the mode is swapped back to its original mode, whether that was text
  or binary.

  See the 'On Windows...' note in the Python docs for more info about text and
  binary mode:
  https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files

  Args:
    file_obj: File-like object to swap to binary mode.

  Yields:
    None.
  Nr   )r  AttributeErrorioUnsupportedOperationr   r3   	IsWindowsr#  setmoder   O_BINARY)file_objr   r#  old_moder   r   r   _FileInBinaryMode}  s   

r0  c                 C   sV   t jr#t|  | | |   W d   dS 1 sw   Y  dS | j| dS )zWrite the given bytes to the stream.

  Args:
    stream: The raw stream to write to, usually sys.stdout or sys.stderr.
    contents: A byte string to write to the stream.
  N)r&   PY2r0  writeflushbuffer)streamr   r   r   r   WriteStreamBytes  s   


"r6  c                   C   sJ   t jrttj tj W  d   S 1 sw   Y  dS tjj S )z|Reads raw bytes from sys.stdin without any encoding interpretation.

  Returns:
    bytes, The byte string that was read.
  N)r&   r1  r0  r]   stdinr   r4  r   r   r   r   ReadStdinBytes  s
   $r8  c                 C   s   | r|du rt d| |t|tjstd|tj| }zt	| W n
 tj
y2   Y nw tj rBt| |d|d dS tjd|dd}|| |  t|j|  W d   dS 1 sfw   Y  dS )	a  Writes a file to disk safely cross platform.

  Specified directories will be created if they don't exist.

  Writes a file to disk safely cross platform. Note that on Windows, there
  is no good way to atomically write a file to disk.

  Args:
    file_name: The actual file to write to.
    contents:  The file contents to write.
    convert_invalid_windows_characters: bool, Convert invalid Windows path
        characters with an 'unsupported' symbol rather than trigger an OSError
        on Windows (e.g. "file|.txt" -> "file$.txt").

  Raises:
    ValueError: file_name or contents is empty.
    TypeError: contents is not a valid string.
  Nz&Empty file_name [{}] or contents [{}].zInvalid contents [{}].T)privater=   wF)r2   dirdelete)r   r8   ra   r&   r   	TypeErrorr   r   r   r   errorr   r3   r+  WriteFileContentsr   NamedTemporaryFiler2  r3  r{   r+   )	file_namer   r=   r   	temp_filer   r   r   WriteFileAtomically  s6   


"rC  c                 C   sf   d}|du r
dd }t t| D ]}|d D ]}t j|d |}||r/|t j|7 }qq|S )zEReturns sum of sizes of not-ignored files under given path, in bytes.r   Nc                 S   rY   rZ   r   xr   r   r   r[     r\   z"GetTreeSizeBytes.<locals>.<lambda>rA   )r   r   r&   r'   r   r   getsize)r   	predicateresultr   rA  r   r   r   r   GetTreeSizeBytes  s   rI  c                 c   s    |st }|du rdd }|du rdd }ttt| D ](\}}}|| |r2|D ]}|V  q,||D ]}	tj||	}
||
rF|
V  q6qdS )a6  Yields a generator that list all the files in a directory tree.

  Walks directory tree from path and yeilds all files that it finds. Will expand
  paths relative to home dir e.g. those that start with '~'.

  Args:
    path: string, base of file tree to walk.
    include_dirs: bool, if true will yield directory names in addition to files.
    file_predicate: function, boolean function to determine which files should
      be included in the output. Default is all files.
    dir_sort_func: function, function that will determine order directories are
      processed. Default is lexical ordering.
    file_sort_func:  function, function that will determine order directories
      are processed. Default is lexical ordering.
  Yields:
    Generator: yields all files and directory paths matching supplied criteria.
  Nc                 S   rY   rZ   r   rD  r   r   r   r[   #  r\   z)GetDirectoryTreeListing.<locals>.<lambda>c                 S   s   |   S rs   )r   rD  r   r   r   r[   %  s    )sortedr   r   ExpandHomeDirr&   r'   r   r   )r   include_dirsfile_predicatedir_sort_funcfile_sort_funcr   r   r   r   rA  r   r   r   r   GetDirectoryTreeListing
  s&   rP  c              
   C   b   zt | }| W  d   W S 1 sw   Y  W dS  ty0 } ztd| |d}~ww )zReads the text contents from the given path.

  Args:
    path: str, The file path to read.

  Raises:
    Error: If the file cannot be read.

  Returns:
    str, The text string read from the file.
  NUnable to read file [{0}]: {1})
FileReaderr   r$   r   r8   r   r   rW   r   r   r   ReadFileContents2     
(rU  c              
   C   rQ  )zReads the binary contents from the given path.

  Args:
    path: str, The file path to read.

  Raises:
    Error: If the file cannot be read.

  Returns:
    bytes, The byte string read from the file.
  NrR  )r   r   r$   r   r8   rT  r   r   r   ReadBinaryFileContentsG  rV  rW  Tc           	   
   C   s   z+t | | t| ||||d}|t| W d   W dS 1 s$w   Y  W dS  ty? } ztd| |d}~ww )a  Writes the given text contents to a file at the given path.

  Args:
    path: str, The file path to write to.
    contents: str, The text string to write.
    overwrite: bool, False to error out if the file already exists.
    private: bool, True to make the file have 0o600 permissions.
    create_path: bool, True to create intermediate directories, if needed.
    newline: str, The line ending style to use, or None to use platform default.
    convert_invalid_windows_characters: bool, Convert invalid Windows path
        characters with an 'unsupported' symbol rather than trigger an OSError
        on Windows (e.g. "file|.txt" -> "file$.txt").

  Raises:
    Error: If the file cannot be written.
  )r9  create_pathnewliner=   NUnable to write file [{0}]: {1})_CheckOverwriter  r2  r   r   r$   r   r8   )	r   r   	overwriter9  rX  rY  r=   r   rW   r   r   r   r?  \  s    
&r?  c              
   C   sx   z't | | t| |||d}|| W d   W dS 1 s w   Y  W dS  ty; } ztd| |d}~ww )av  Writes the given binary contents to a file at the given path.

  Args:
    path: str, The file path to write to.
    contents: str, The byte string to write.
    overwrite: bool, False to error out if the file already exists.
    private: bool, True to make the file have 0o600 permissions.
    create_path: bool, True to create intermediate directories, if needed.
    convert_invalid_windows_characters: bool, Convert invalid Windows path
        characters with an 'unsupported' symbol rather than trigger an OSError
        on Windows (e.g. "file|.txt" -> "file$7.txt").

  Raises:
    Error: If the file cannot be written.
  r9  rX  r=   NrZ  )r[  BinaryFileWriterr2  r$   r   r8   )r   r   r\  r9  rX  r=   r   rW   r   r   r   WriteBinaryFileContents  s   
&r_  c                 C   s&   |st j| rtd| d S d S )Nz3File [{0}] already exists and cannot be overwritten)r   r   rz   r   r8   )r   r\  r   r   r   r[    s
   r[  c                 C   s   t | ddddS )zOpens the given file for text read for use in a 'with' statement.

  Args:
    path: str, The file path to read from.

  Returns:
    A file-like object opened for read in text mode.
  rtr   utf-8r   _FileOpenerr   r   r   r   rS    s   	rS  c                 C   s   t tj| ddddS )zOpens the given file for binary read for use in a 'with' statement.

  Args:
    path: str, The file path to read from.

  Returns:
    A file-like object opened for read in binary mode.
  ra  r   rbr   )rc  r   Encoder   r   r   r   r     s   	r   c              
   C   s$   |rdnd}t | |dd||||dS )a  Opens the given file for text write for use in a 'with' statement.

  Args:
    path: str, The file path to write to.
    private: bool, True to create or update the file permission to be 0o600.
    append: bool, True to append to an existing file.
    create_path: bool, True to create intermediate directories, if needed.
    newline: str, The line ending style to use, or None to use plaform default.
    convert_invalid_windows_characters: bool, Convert invalid Windows path
        characters with an 'unsupported' symbol rather than trigger an OSError
        on Windows (e.g. "file|.txt" -> "file$7.txt").

  Returns:
    A file-like object opened for write in text mode.
  atwtr2  ra  )r   r9  rX  rY  r=   rb  )r   r9  r%   rX  rY  r=   r2   r   r   r   r    s   r  c                   @   s   e Zd ZdZdZdZdS )BinaryFileWriterModeabzr+bwbN)r   r   r   APPENDMODIFYTRUNCATEr   r   r   r   rh    s    rh  c                 C   s   t | |jd|||dS )ap  Opens the given file for binary write for use in a 'with' statement.

  Args:
    path: str, The file path to write to.
    private: bool, True to create or update the file permission to be 0o600.
    mode: BinaryFileWriterMode, Determines how to open file for writing.
    create_path: bool, True to create intermediate directories, if needed.
    convert_invalid_windows_characters: bool, Convert invalid Windows path
        characters with an 'unsupported' symbol rather than trigger an OSError
        on Windows (e.g. "file|.txt" -> "file$7.txt").

  Returns:
    A file-like object opened for write in binary mode.
  r2  r]  )rc  r   )r   r9  r2   rX  r=   r   r   r   r^    s   r^  c           
   
   C   s   |rt j t jjkrt | } |rt|  |rt|  z
tj| |||dW S  t	yJ } zt
}	t|tr=|jtjkr=t}	|	d|| |d}~ww )z6Opens a file in various modes and does error handling.)r   rY  zUnable to {0} file [{1}]: {2}N)r   r3   r4   r5   r6   PrivatizeFile_MakePathToFiler)  r   r$   r   ra   r  r9   r   r   r8   )
r   r2   verbr   r9  rX  rY  r=   rW   r  r   r   r   rc    s    	
rc  c                   C   s   t dS )z-Returns the current user HOME directory path.~)rK  r   r   r   r   
GetHomeDir(  s   rr  c                 C   s   t tj| S )z:Returns path with leading ~<SEP> or ~<USER><SEP> expanded.)r   r   r   r   
expanduserr   r   r   r   rK  -  s   rK  c                 C   s   t tjt| S )zExpands ~ and ENV_VARS in path.)r   r   r   r   
expandvarsrK  r   r   r   r   ExpandHomeAndVars2  s   ru  c                 C   s$   t jjjj}tjtj|| S )z7Converts url to path string and normalizes path string.)	r&   movesurllibrequesturl2pathnamer   r   r   r   )urlry  r   r   r   NormalizePathFromURL7  s   r{  c                 C   s.   t j| \}}t jt|}t|| d S rs   )r   r   r   r~   rK  r@   )r   r2   parent_dir_pathr   full_parent_dir_pathr   r   r   ro  =  s   ro  c              
   C   s   z7t j| rt | d W dS t| dd t jt jB t jB }tt dr)|t j	O }t 
| |d}t | W dS  tyK } ztd| |d}~ww )a  Makes an existing file private or creates a new, empty private file.

  In theory it would be better to return the open file descriptor so that it
  could be used directly. The issue that we would need to pass an encoding to
  os.fdopen() and on Python 2. This is not supported. Instead we just create
  the empty file and then we will just open it normally later to do the write.

  Args:
    path: str, The path of the file to create or privatize.
  i  i  r1   O_NOINHERITz(Unable to create private file [{0}]: {1}N)r   r   rz   rf   ro  r   r   O_TRUNChasattrr~  r   r   r$   r   r8   )r   flagsr   rW   r   r   r   rn  C  s   

rn  c                 c   sJ    t | }|D ]
}||r|V  qW d   dS 1 sw   Y  dS )z/Read all lines from a text file matching regex.N)rS  match)r   regexr   liner   r   r   FilteredFileReader`  s   

"r  )r0   Frs   )NNFr   )FNNN)TFTNF)TFTF)FFFNF)NFFNF)r0   )Yr   
__future__r   r   r   
contextlibenumr9   r   r)  rC   r   r    rg   r]   r   rE   googlecloudsdk.corer   googlecloudsdk.core.utilr   r   r   r	   r&   	six.movesr
   rB   rR   	NameError	Exceptionr   r   r   r@   rI   rT   rX   r_   rk   rr   rx   r}   r   r   r   r   r   r   r   r   r   objectr   r   r   r   r   r   r   r  r  contextmanagerr0  r6  r8  rC  rI  rP  rU  rW  r?  r_  r[  rS  r   r  Enumrh  rm  r^  rc  rr  rK  ru  r{  ro  rn  r  r   r   r   r   <module>   s   
)$
! %
!!
.@)za
&

:
(
.
$
!


