o
    d                     @   s   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m	Z	 ddl
m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dAddZdd ZdBddZdd Zdd Zdd ZG dd deZeejG dd deZG dd deZG dd  d eZG d!d" d"eZG d#d$ d$eZ G d%d& d&eZ!G d'd( d(eZ"G d)d* d*eZ#eejG d+d, d,eZ$G d-d. d.e$Z%G d/d0 d0e$Z&G d1d2 d2e$Z'G d3d4 d4e'Z(G d5d6 d6e'Z)G d7d8 d8e)Z*G d9d: d:e$Z+G d;d< d<e$Z,G d=d> d>e$Z-G d?d@ d@e$Z.dS )Cz8Cloud resource list filter expression evaluator backend.    )absolute_import)division)unicode_literalsN)log)resource_exceptions)resource_lex)resource_property)encoding)timesc              
   C   s<   zt | |W S  t jy } z	td| |d}~ww )zReturns a compiled RE pattern.

  Args:
    pattern: The RE pattern string.
    flags: Optional RE flags.

  Raises:
    ExpressionSyntaxError: RE pattern error.

  Returns:
    The compiled RE.
  z%Filter expression RE pattern [{}]: {}N)recompileerrorr   ExpressionSyntaxErrorformat)patternflagse r   G/tmp/google-cloud-sdk/lib/googlecloudsdk/core/resource/resource_expr.py
_ReCompile$   s   
r   c                 C   s0   | du rdS t | tjst| } tt| S )z4Returns the unicode string representation for value.Nnull)
isinstancesixstring_typesrepr	text_typer	   Decodevaluer   r   r   
_Stringize8   s
   r   Fc                 C   s:   t |  }|rtdd|}ddd td|D S )a$  Returns lowercase unicode NFKD form with accents stripped.

  Args:
    value: The value to be normalized.
    html: If True the value is HTML text and HTML tags are converted to spaces.

  Returns:
    The normalized unicode representation of value suitable for cloud search
    matching.
  z<[^>]*> c                 S   s   g | ]	}t |s|qS r   )unicodedata	combining).0cr   r   r   
<listcomp>R   s    
z&NormalizeForSearch.<locals>.<listcomp>NFKD)r   lowerr   subjoinr!   	normalize)r   htmltextr   r   r   NormalizeForSearchA   s   r-   c                 C   s>   t | ts
t | tr| S zt| W S  ty   t|  Y S w )z-Returns value converted to int or float type.)r   intfloat
ValueErrorr   r   r   r   _NumericTypeV   s   
r1   c              
   C   s  |\}}}t |ttfrCz|t|krW dS W n	 ty    Y nw |dkr-| dkr-dS |dkr9| dkr9dS tddt|}	nX||krIdS |du r`|d	v rSdS |d
kr]|dkr]dS d}	n;|rt |t	j
j
rz|jrpt	jnd}
|t	j||
dkr~W dS W n tt	jt	jfy   Y nw t|dd}	nt|dd}	t||	}|s|S t||	}t|dkr|d dv r|t||	dd O }||kr|rt| |dst| |d |rdnd}|rdnd}tdjt|||||d |S )a'  Returns True if value word matches pattern.

  Args:
    backend: The parser backend object.
    key: The parsed expression key.
    op: The expression operator string.
    warned_attribute: Deprecation warning Boolean attribute name.
    value: The value to be matched by pattern.
    pattern: An (operand, standard_regex, deprecated_regex) tuple.

  Raises:
    ValueError: To catch codebase reliance on deprecated usage.

  Returns:
    True if pattern matches value.

  Examples:
    See surface/topic/filters.py for a table of example matches.
  Tr   false   truez\.0*$r    N)r    N*:Fr   tzinfo)r+   )zoneregion/matcheszdoes not matchz
will matchzwill not matchz--filter : operator evaluation is changing for consistency across Google APIs.  {key}{op}{operand} currently {old_match} but {new_match} in the near future.  Run `gcloud topic filters` for details.)keyopoperand	old_match	new_match)r   r.   r/   r1   r0   r'   r   r(   r   r
   datetimer8   LOCALParseDateTimeDateTimeSyntaxErrorDateTimeValueErrorr-   boolsearchlensplitgetattrsetattrr   warningr   r   
GetKeyName)backendr>   r?   warned_attributer   r   r@   standard_regexdeprecated_regexr,   r8   matcheddeprecated_matchedrA   rB   r   r   r   _MatchOneWordInTexta   sl   

	rV   c           
   	   C   s   t |trd}g }|r|t| |t| nt |ttfr&|}n|g}t |ttfr3|}n|h}|D ]}|D ]}	t| |||||	rK  dS q<q8dS )a  Applies _MatchOneWordInText to determine if value matches pattern.

  Both value and operand can be lists.

  Args:
    backend: The parser backend object.
    key: The parsed expression key.
    op: The expression operator string.
    warned_attribute: Deprecation warning Boolean attribute name.
    value: The key value or list of values.
    pattern: Pattern value or list of values.

  Returns:
    True if the value (or any element in value if it is a list) matches pattern
    (or any element in operand if it is a list).
  NTF)	r   dictextendr   iterkeys
itervalueslisttuplerV   )
rP   r>   r?   rQ   r   r   valuespatternsvpr   r   r   
_WordMatch   s(   
ra   c                   @   s   e Zd Z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#ddZd#ddZd#ddZd#ddZd#ddZd#ddZd#ddZd#dd Zd!d" ZdS )$Backenda  Cloud resource list filter expression evaluator backend.

  This is a backend for resource_filter.Parser(). The generated "evaluator" is a
  parsed resource expression tree with branching factor 2 for binary operator
  nodes, 1 for NOT and function nodes, and 0 for TRUE nodes. Evaluation for a
  resource object starts with expression_tree_root.Evaluate(obj) which
  recursively evaluates child nodes. The logic operators use left-right shortcut
  pruning, so an evaluation may not visit every node in the expression tree.
  c                 C   s   t | S N)	_ExprTRUEselfr   r   r   ExprTRUE      zBackend.ExprTRUEc                 C      t | ||S rc   )_ExprANDrf   leftrightr   r   r   ExprAND      zBackend.ExprANDc                 C   ri   rc   )_ExprORrk   r   r   r   ExprOR   ro   zBackend.ExprORc                 C   
   t | |S rc   )_ExprNOT)rf   exprr   r   r   ExprNOT      
zBackend.ExprNOTc                 C   rr   rc   )_ExprGlobal)rf   callr   r   r   
ExprGlobal   rv   zBackend.ExprGlobalc                 C   rr   rc   )_ExprOperandrf   r   r   r   r   ExprOperand   rv   zBackend.ExprOperandNc                 C      t | |||S rc   )_ExprLTrf   r>   r@   	transformr   r   r   ExprLT      zBackend.ExprLTc                 C   r}   rc   )_ExprLEr   r   r   r   ExprLE  r   zBackend.ExprLEc                 C   r}   )a  Case insensitive membership node.

    This is the pre-compile Expr for the ':' operator. It compiles into an
    _ExprHAS node for prefix*suffix matching.

    The * operator splits the operand into prefix and suffix matching strings.

    Args:
      key: Resource object key (list of str, int and/or None values).
      operand: The term ExprOperand operand.
      transform: Optional key value transform calls.

    Returns:
      _ExprHAS.
    )_ExprHASr   r   r   r   ExprHAS  s   zBackend.ExprHASc                 C   r}   )zCase sensitive EQ node.

    Args:
      key: Resource object key (list of str, int and/or None values).
      operand: The term ExprOperand operand.
      transform: Optional key value transform calls.

    Returns:
      _ExprEQ.
    )_ExprEQr   r   r   r   ExprEQ  s   zBackend.ExprEQc                 C   r}   rc   )_ExprNEr   r   r   r   ExprNE$  r   zBackend.ExprNEc                 C   r}   rc   )_ExprGEr   r   r   r   ExprGE'  r   zBackend.ExprGEc                 C   r}   rc   )_ExprGTr   r   r   r   ExprGT*  r   zBackend.ExprGTc                 C   r}   rc   )_ExprREr   r   r   r   ExprRE-  r   zBackend.ExprREc                 C   r}   rc   )
_ExprNotREr   r   r   r   	ExprNotRE0  r   zBackend.ExprNotREc                 C      dS NFr   re   r   r   r   
IsRewriter3     zBackend.IsRewriterrc   )__name__
__module____qualname____doc__rg   rn   rq   ru   ry   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rb      s$    








rb   c                   @   s2   e Zd ZdZdd Zejdd Zedd Z	dS )	_ExprzExpression base class.c                 C   s
   || _ d S rc   )rP   )rf   rP   r   r   r   __init__>  rv   z_Expr.__init__c                 C   r   )zReturns the value of the subexpression applied to obj.

    Args:
      obj: The current resource object.

    Returns:
      True if the subexpression matches obj, False if it doesn't match, or
      None if the subexpression is not supported.
    Nr   rf   objr   r   r   EvaluateA     z_Expr.Evaluatec                 C   r   r   r   re   r   r   r   contains_keyN     z_Expr.contains_keyN)
r   r   r   r   r   abcabstractmethodr   propertyr   r   r   r   r   r   :  s    
r   c                   @      e Zd ZdZdd ZdS )rd   z'TRUE node.

  Always evaluates True.
  c                 C   r   NTr   )rf   
unused_objr   r   r   r   Y  r   z_ExprTRUE.EvaluateNr   r   r   r   r   r   r   r   r   rd   S      rd   c                       s    e Zd ZdZ fddZ  ZS )_ExprLogicalziBase logical operator node.

  Attributes:
    left: Left Expr operand.
    right: Right Expr operand.
  c                    s    t t| | || _|| _d S rc   )superr   r   _left_right)rf   rP   rl   rm   	__class__r   r   r   e  s   
z_ExprLogical.__init__)r   r   r   r   r   __classcell__r   r   r   r   r   ]  s    r   c                   @   r   )rj   z8AND node.

  AND with left-to-right shortcut pruning.
  c                 C   s$   | j |sdS | j|sdS dS )NFTr   r   r   r   r   r   r   r   q  
   z_ExprAND.EvaluateNr   r   r   r   r   rj   k  r   rj   c                   @   r   )rp   z6OR node.

  OR with left-to-right shortcut pruning.
  c                 C   s$   | j |rdS | j|rdS dS )NTFr   r   r   r   r   r     r   z_ExprOR.EvaluateNr   r   r   r   r   rp   y  r   rp   c                       (   e Zd ZdZ fddZdd Z  ZS )rs   z	NOT node.c                       t t| | || _d S rc   )r   rs   r   _expr)rf   rP   rt   r   r   r   r        
z_ExprNOT.__init__c                 C   s   | j | S rc   )r   r   r   r   r   r   r     r   z_ExprNOT.Evaluater   r   r   r   r   r   r   r   r   r   r   rs         rs   c                       r   )rw   z]Global restriction function call node.

  Attributes:
    _call: The function call object.
  c                    r   rc   )r   rw   r   _call)rf   rP   rx   r   r   r   r     r   z_ExprGlobal.__init__c                 C   s   | j |S rc   )r   r   r   r   r   r   r     ro   z_ExprGlobal.Evaluater   r   r   r   r   rw     s    rw   c                   @   s.   e Zd ZdZdddZd
ddZd
dd	ZdS )rz   a  Operand node.

  Converts an expession value token string to internal string and/or numeric
  values. If an operand has a numeric value then the actual key values are
  converted to numbers at Evaluate() time if possible for Apply(); if the
  conversion fails then the key and operand string values are passed to Apply().

  Attributes:
    list_value: A list of operands.
    numeric_value: The int or float number, or None if the token string does not
      convert to a number.
    string_value: The token string.
  r   r3   )r2   r4   Nc                 C   s0   || _ d | _d| _d | _d | _| j||d d S )NFr*   )rP   
list_valuenumeric_constantnumeric_valuestring_value
Initialize)rf   rP   r   r*   r   r   r   r     s   z_ExprOperand.__init__c                 C   s   t |trg | _|D ]}| jt| j||d q
dS |r&|r&||| _dS t |tjr[|| _z| j	|
  | _d| _W dS  tyZ   z	t|| _W Y dS  tyV   Y nw Y dS w t|| _|| _dS )zInitializes an operand string_value and numeric_value from value.

    Args:
      value: The operand expression string value.
      normalize: Optional normalization function.
    r   TN)r   r[   r   appendrz   rP   r   r   r   _NUMERIC_CONSTANTSr'   r   r   KeyErrorr1   r0   r   )rf   r   r*   valr   r   r   r     s0   


z_ExprOperand.Initializerc   )r   r   r   r   r   r   r   r   r   r   r   rz     s    
rz   c                       sr   e Zd ZdZejjejjejjejj	fZ
 fddZdd Zedd Zedd	 Zd
d Zejdd Z  ZS )_ExprOperatora  Base term (<key operator operand>) node.

  ExprOperator subclasses must define the function Apply(self, value, operand)
  that returns the result of <value> <op> <operand>.

  Attributes:
    _key: Resource object key (list of str, int and/or None values).
    _normalize: The resource value normalization function.
    _operand: The term ExprOperand operand.
    _transform: Optional key value transform calls.
    key : Property decorator for the resource object key.
  c                    s@   t t| | || _|| _|| _|rdd | _d S | j| _d S )Nc                 S      | S rc   r   xr   r   r   <lambda>      z(_ExprOperator.__init__.<locals>.<lambda>)r   r   r   _key_operand
_transform
_normalizeInitializeNormalizationrf   rP   r>   r@   r   r   r   r   r     s   z_ExprOperator.__init__c                    s|   dd | _ td|r<z&t|}|jrtjnd | jj| jj	p#| jj
 fddd tj| _ W |S  ty;   Y |S w |S )a  Checks the first non-empty resource value to see if it can be normalized.

    This method is called at most once on the first non-empty resource value.
    After that a new normalization method is set for the remainder of the
    resource values.

    Resource values are most likely well defined protobuf string encodings. The
    RE patterns match against those.

    Args:
      value: A resource value to normalize.

    Returns:
      The normalized value.
    c                 S   r   rc   r   r   r   r   r   r   
  r   z7_ExprOperator.InitializeNormalization.<locals>.<lambda>z$\d\d\d\d-\d\d-\d\d[ T]\d\d:\d\d:\d\dNc                    s   t j|  dS )Nr7   )r
   rE   r   r7   r   r   r     s    r   )r   r   matchr
   rE   r8   rD   r   r   r   r   r0   r{   r   r7   r   r     s    



z%_ExprOperator.InitializeNormalizationc                 C   r   r   r   re   r   r   r   r     r   z_ExprOperator.contains_keyc                 C   s   | j S rc   )r   re   r   r   r   r>   #  s   z_ExprOperator.keyc                 C   s  t || j}| jr| j|}|rt|ttfr|}n|g}g }|D ]}|r:z| |}W n t	t
fy9   Y nw || q#| jjrI| jj}n| jg}|D ]}|D ]}|jdur{z| t||jriW   dS |jsnW qSW n t	t
fyz   Y nw |st|j| jrqSz| ||jrW   dS W qS tt
fy   Y qS t	y   |durt|tjttfs| t||jrY   dS tjr|du r| d|jrY   dS Y qSw qOdS )zEvaluate a term node.

    Args:
      obj: The resource object to evaluate.
    Returns:
      The value of the operator applied to the key value and operand.
    NTr    F)r   Getr   r   r   r   r[   r\   r   	TypeErrorr0   r   r   r   r   Applyr1   r   r   _TIME_TYPESAttributeErrorr   r   rW   r   PY3)rf   r   r   resource_valuesr]   operandsr@   r   r   r   r   '  sn   





#z_ExprOperator.Evaluatec                 C   r   )zReturns the value of applying a <value> <operator> <operand> term.

    Args:
      value: The term key value.
      operand: The term operand value.

    Returns:
      The Boolean value of applying a <value> <operator> <operand> term.
    Nr   rf   r   r@   r   r   r   r   l  r   z_ExprOperator.Apply)r   r   r   r   r
   rC   datetime	timedeltar8   r   r   r   r   r   r>   r   r   r   r   r   r   r   r   r   r     s     
%

Er   c                   @   r   )r~   zLT node.c                 C   s   ||k S rc   r   r   r   r   r   r   }  rh   z_ExprLT.ApplyNr   r   r   r   r   r   r   r   r   r~   z      r~   c                   @   r   )r   zLE node.c                 C   s   ||kS rc   r   r   r   r   r   r     rh   z_ExprLE.ApplyNr   r   r   r   r   r     r   r   c                       s<   e Zd ZdZ		d	 fdd	Zejdd Zdd Z  Z	S )
_ExprWordMatchBasez${ HAS EQ NE } word match base class.Nc                    s   t t| |||| || _|| _g | _| jjd ur2| jjD ]}|jd ur/|j|_| 	|j qd S | jjd urE|j|_| 	| jj d S d S rc   )
r   r   r   _op_warned_attribute	_patternsr   r   r   _AddPattern)rf   rP   r>   r@   r   r?   rQ   r   r   r   r     s   
z_ExprWordMatchBase.__init__c                 C   r   )z,Adds a word match pattern to self._patterns.Nr   )rf   r   r   r   r   r     s   z_ExprWordMatchBase._AddPatternc                 C   s   t | j| j| j| j|| jS )aQ  Checks if value word matches operand ignoring case differences.

    Args:
      value: The number, string, dict or list object value.
      operand: Non-pattern operand for equality check. The ':' HAS operator
        operand can be a prefix*suffix pattern or a literal value. Literal
        values are first checked by the _Equals method to handle numeric
        constant matching. String literals and patterns are then matched by the
        _Has method.

    Returns:
      True if value HAS matches operand (or any value in operand if it is a
      list) ignoring case differences.
    )ra   rP   r   r   r   r   r   r   r   r   r     s   z_ExprWordMatchBase.Apply)NN)
r   r   r   r   r   r   r   r   r   r   r   r   r   r   r     s    
r   c                       r   )r   zHAS word match node.c                    s    t t| j||||ddd d S )Nr6   _deprecated_has_warnedr?   rQ   )r   r   r   r   r   r   r   r     s   
z_ExprHAS.__init__c                 C   s  |dkr	d}d}nd}d}d}t |}|d}t|dkr&td||dr3|dd }d}t|}	||	 | }t|d	krJ|	d n|
drRd}n
|drZd}nd
}|d rgt|d nd}
|d	 rtt|d	 nd}|r|r|rd|
 | | d }n|
| | }n|rd|
 | | }n|r|
| | d }nd}tjtjB tjB }t||}|rt||}nd}| j	|||f dS )ah  Adds a HAS match pattern to self._patterns.

    A pattern is a word that optionally contains one trailing * that matches
    0 or more characters.

    This method re-implements both the original and the OnePlatform : using REs.
    It was tested against the original tests with no failures.  This cleaned up
    the code (really!) and made it easier to reason about the two
    implementations.

    Args:
      pattern: A string containing at most one trailing *.

    Raises:
      resource_exceptions.ExpressionSyntaxError if the pattern contains more
        than one leading or trailing * glob character.
    r5   .N\br       z*At most one * expected in : patterns [{}].r<   r3   z.*r   ^$)r-   rK   rJ   r   r   r   endswithr   escaper   
startswith
IGNORECASE	MULTILINEUNICODEr   r   )rf   r   standard_patterndeprecated_patternheadglobtailnormalized_patternpartswordrl   rm   reflagsrR   rS   r   r   r   r     sR   





z_ExprHAS._AddPatternr   r   r   r   r   r   r   r   r   r   r   r     r   r   c                       s*   e Zd ZdZd fdd	Zdd Z  ZS )r   zEQ word match node.Nc                    s$   t t| j|||||pddd d S )N=_deprecated_eq_warnedr   )r   r   r   )rf   rP   r>   r@   r   r?   r   r   r   r     s   
z_ExprEQ.__init__c           	      C   sf   t |}t|}d| d }d| d }tjtjB tjB }t||}t||}| j|||f dS )a  Adds an EQ match pattern to self._patterns.

    A pattern is a word.

    This method re-implements both the original and the OnePlatform = using REs.
    It was tested against the original tests with no failures.  This cleaned up
    the code (really!) and made it easier to reason about the two
    implementations.

    Args:
      pattern: A string containing a word to match.
    r   r   r   N)	r-   r   r   r   r   r   r   r   r   )	rf   r   r   r   r   r   r   rR   rS   r   r   r   r     s   


z_ExprEQ._AddPatternrc   r   r   r   r   r   r      s    r   c                       s,   e Zd ZdZ fddZ fddZ  ZS )r   zNE node.c                    s   t t| j||||dd d S )Nz!=)r?   )r   r   r   r   r   r   r   r   '  s   z_ExprNE.__init__c                    s   t t| || S rc   )r   r   r   r   r   r   r   r   *  s   z_ExprNE.Applyr   r   r   r   r   r   r   r   r   r   r   r   $  s    r   c                   @   r   )r   zGE node.c                 C   s   ||kS rc   r   r   r   r   r   r   1  rh   z_ExprGE.ApplyNr   r   r   r   r   r   .  r   r   c                   @   r   )r   zGT node.c                 C   s   ||kS rc   r   r   r   r   r   r   8  rh   z_ExprGT.ApplyNr   r   r   r   r   r   5  r   r   c                       r   )r   zUnanchored RE match node.c                    (   t t| |||| t| jj| _d S rc   )r   r   r   r   r   r   r   r   r   r   r   r   ?     z_ExprRE.__init__c                 C   s$   t |tjs
td| j|d uS Nz(RE match subject value must be a string.r   r   r   r   r   rI   rf   r   unused_operandr   r   r   r   C     z_ExprRE.Applyr   r   r   r   r   r   <  r   r   c                       r   )r   zUnanchored RE not match node.c                    r   rc   )r   r   r   r   r   r   r   r   r   r   r   r   M  r   z_ExprNotRE.__init__c                 C   s$   t |tjs
td| j|d u S r  r  r  r   r   r   r   Q  r  z_ExprNotRE.Applyr   r   r   r   r   r   J  r   r   )r   )F)/r   
__future__r   r   r   r   r   r!   googlecloudsdk.corer   googlecloudsdk.core.resourcer   r   r   googlecloudsdk.core.utilr	   r
   r   r   r   r-   r1   rV   ra   objectrb   add_metaclassABCMetar   rd   r   rj   rp   rs   rw   rz   r   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sV   

	V)
Z

9  +M$
