
                             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ZdZ	 G d d	e
      Z G d
 de      Zd Zd Zd Z G d de      Zy)a  Library for ignoring files for upload.

This library very closely mimics the semantics of Git's gitignore file:
https://git-scm.com/docs/gitignore

See `gcloud topic gcloudignore` for details.

A typical use would be:

  file_chooser = gcloudignore.GetFileChooserForDir(upload_directory)
  for f in file_chooser.GetIncludedFiles('some/path'):
    print 'uploading {}'.format(f)
    # actually do the upload, too
    )absolute_import)division)unicode_literalsN/z(?<!\\)\\(\\\\)*$c                       e Zd ZdZy)InternalParserErrorz*An internal error in gcloudignore parsing.N__name__
__module____qualname____doc__     +lib/googlecloudsdk/command_lib/util/glob.pyr   r   *   s    2r   r   c                       e Zd ZdZy)InvalidLineErrorz<Error indicating that a line of the ignore file was invalid.Nr	   r   r   r   r   r   .   s    Dr   r   c                 *    d }d } | ||             S )a   Handles spaces in a line.

  In particular, deals with trailing spaces (which are stripped unless
  escaped) and escaped spaces throughout the line (which are unescaped).

  Args:
    line: str, the line

  Returns:
    str, the line with spaces handled
  c                    g }d}|t        |       k  rr| |   }|dk(  rC|dz   t        |       k\  r|j                  |       nE|j                  || |dz      z          |dz  }n|j                  |       |dz  }|t        |       k  rrg }d}t        |      D ]  }|r|dk(  rd}|j                  |        dj                  t        |            S )	z!Strips unescaped trailing spaces.r   \      T F )lenappendreversedjoin)linetokensicurrresonly_seen_spacess         r   _Rstripz_HandleSpaces.<locals>._Rstrip>   s     F	A
c$i-!Wd	q5CI
--

dT!A#Y&'	Qd	Q c$i- C 	dck	jj	 ! 778C=!!r   c                 &    | j                  dd      S )zUnescapes all spaces in a line.z\ r   )replacer   s    r   _UnescapeSpacesz&_HandleSpaces.<locals>._UnescapeSpaces[   s    <<s##r   r   )r   r$   r(   s      r   _HandleSpacesr)   2   s    ":$ 
	''r   c                 P    t        j                  dd|       j                  dd      S )zUnescapes a line.

  The escape character is '\'. An escaped backslash turns into one backslash;
  any other escaped character is ignored.

  Args:
    line: str, the line to unescape

  Returns:
    str, the unescaped line

  z	\\([^\\])z\1z\\r   )resubr&   r'   s    r   	_Unescaper-   b   s$     
eT	*	2	264	@@r   c                     | g}d}| r;|r9t         j                  j                  |       \  } }|j                  d|        | r|r9|S )zReturns all prefixes for the given path, inclusive.

  That is, for 'foo/bar/baz', returns ['', 'foo', 'foo/bar', 'foo/bar/baz'].

  Args:
    path: str, the path for which to get prefixes.

  Returns:
    list of str, the prefixes.
  Tr   )ospathsplitinsert)r0   path_prefixespath_reminders      r   GetPathPrefixesr5   r   sM     &-- 	''---D-D! 	 
r   c                   6    e Zd ZdZddZd ZddZed        Zy)GlobzA file-matching glob pattern.

  See https://git-scm.com/docs/gitignore for full syntax specification.

  Attributes:
    pattern: str, a globbing pattern.
    must_be_dir: bool, true if only dirs match.
  c                      || _         || _        y N)patternmust_be_dir)selfr:   r;   s      r   __init__zGlob.__init__   s    DL"Dr   c                     |sy|y|d   }|dd |rt         j                  j                  |      }t         j                  j                  |      \  }}|sd}|dk(  r<t	        |      }rd   dk(  sj                  dd       t         fd|D              S |d	k(  rs|rt        |      d
kD  ryt        j                  ||      sy j                  |      S )aR  Determines whether the given pattern matches the given path.

    Args:
      pattern_parts: list of str, the list of pattern parts that must all match
        the path.
      path: str, the path to match.

    Returns:
      bool, whether the patch matches the pattern_parts (Matches() will convert
        this into a Match value).
    TNFz**r   r   c              3   B   K   | ]  }j                  |        y wr9   )_MatchesHelper).0prefixremaining_patternr<   s     r   	<genexpr>z&Glob._MatchesHelper.<locals>.<genexpr>   s)      #! EK$$%6?!s   *r   )
r/   r0   normpathr1   r5   r2   anyr   fnmatchrA   )r<   pattern_partsr0   pattern_partremaining_path	path_partr3   rD   s   `      @r   rA   zGlob._MatchesHelper   s     |  $L%cr*WWd#d "d 3NInt &d+m  $5a$8B$>  B' #!# # # s#4
 
C/!3??9l3 0.AAr   c                 z    | j                   r|sy| j                  | j                  j                  d      |      ryy)z4Returns a Match for this pattern and the given path.Fr   T)r;   rA   r:   r1   )r<   r0   is_dirs      r   MatcheszGlob.Matches   s5    4<<--c2D9r   c                    |j                  d      r|dd }d}nd}t        |      }t        j                  t        |      rt        dj                  |            t        |      }|st        dj                  |             | ||      S )	a4  Creates a pattern for an individual line of an ignore file.

    Windows-style newlines must be removed.

    Args:
      line: str, The line to parse.

    Returns:
      Pattern.

    Raises:
      InvalidLineError: if the line was invalid (comment, blank, contains
        invalid consecutive stars).
    r   Nr?   TFz(Line [{}] ends in an odd number of [\]s.zLine [{}] is blank.)r;   )endswithr)   r+   search_ENDS_IN_ODD_NUMBER_SLASHES_REr   formatr-   )clsr   r;   s      r   
FromStringzGlob.FromString   s      }}S#2YdkkD	yy/6
5
<
<T
BD DT?D299$?@@t--r   N)F)	r
   r   r   r   r=   rA   rP   classmethodrW   r   r   r   r7   r7      s-    #ABF . .r   r7   )r   
__future__r   r   r   rI   r/   r+   _GCLOUDIGNORE_PATH_SEPrT   	Exceptionr   r   r)   r-   r5   objectr7   r   r   r   <module>r]      sd    '  '  	 	 !5 3) 3E* E-(`A *v.6 v.r   