o
                         @   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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ddlmZ ddlmZ ddlmZ ddlZdZedZedjedZedZdZdZd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%G d$d% d%ej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 d0d1 d1e,Z-G d2d3 d3e,Z.d4d5 Z/d6d7 Z0G d8d9 d9e&Z1G d:d; d;e1Z2G d<d= d=e1Z3G d>d? d?e1Z4G d@dA dAe1Z5G dBdC dCe1Z6G dDdE dEe,Z7dFdG Z8G dHdI dIe,Z9e9 Z:dJdK Z;dLdM Z<dNdO Z=dPdQ Z>dS )Raj  Manage parsing resource arguments for the cloud platform.

The Parse() function and Registry.Parse() method are to be used whenever a
Google Cloud API resource is indicated in a command-line argument.
URLs, bare names with hints, and any other acceptable spelling for a resource
will be accepted, and a consistent python object will be returned for use in
code.
    )absolute_import)division)unicode_literalsN)apis_internal)	apis_util)resource)
exceptions)
properties)map)urllib)zipz[a-zA-Z_]+(?:\.[a-zA-Z0-9_]+)+z!(https?://[^/]+/[^/]+/[^/]+/)(.+)z!(?P<collection>{collection})\.get
collectionz^gs://([^/]*)(?:/(.*))?$z&https://www.googleapis.com/storage/v1/z*https://storage.googleapis.com/storage/v1/zhttps://storage.googleapis.com/c                   @      e Zd ZdZdS )ErrorzExceptions for this module.N__name__
__module____qualname____doc__ r   r   :/tmp/google-cloud-sdk/lib/googlecloudsdk/core/resources.pyr   8       r   c                   @   r   )_ResourceWithoutGetExceptionz+Exception for resources with no Get method.Nr   r   r   r   r   r   <   r   r   c                           e Zd ZdZ fddZ  ZS )BadResolverExceptionz6Exception to signal that a resource has no Get method.c                       t t| dj|d d S )Nzbad resolver for [{param}])param)superr   __init__format)selfr   	__class__r   r   r   C      

zBadResolverException.__init__r   r   r   r   r   __classcell__r   r   r"   r   r   @       r   c                       r   )AmbiguousAPIExceptionz5Exception for when two APIs try to define a resource.c                    s"   t t| dj|t|d d S )Nz:collection [{collection}] defined in multiple APIs: {apis})r   apis)r   r(   r   r    repr)r!   r   	base_urlsr"   r   r   r   K   s   
zAmbiguousAPIException.__init__r%   r   r   r"   r   r(   H   r'   r(   c                       r   )AmbiguousResourcePathz<Exception for when API path maps to two different resources.c                    s   t t| d|| d S )NzOThere already exists parser {0} for same path, can not register another one {1})r   r,   r   r    )r!   parser1parser2r"   r   r   r   U   s   
zAmbiguousResourcePath.__init__r%   r   r   r"   r   r,   R   r'   r,   c                       r   )#ParentCollectionResolutionExceptionzMException for when the parent collection cannot be computed automatically.
  c                    s$   t t| dj|d|d d S )NzuCould not resolve the parent collection of collection [{collection}]. No collections found with parameters [{params}], r   params)r   r/   r   r    joinr!   r   r2   r"   r   r   r   _   s   

z,ParentCollectionResolutionException.__init__r%   r   r   r"   r   r/   [       r/   c                       r   )!ParentCollectionMismatchExceptionzGException when the parent collection does not have the expected params.c              	      s.   t t| dj||d|d|d d S )NzThe parent collection [{parent_collection}] of collection [{collection}] does have have the expected parameters. Expected [{expected_params}], found [{actual_params}].r0   )parent_collectionr   expected_paramsactual_params)r   r6   r   r    r3   )r!   r   r7   r8   r9   r"   r   r   r   i   s   
z*ParentCollectionMismatchException.__init__r%   r   r   r"   r   r6   f   r'   r6   c                   @   r   )	UserErrorz)Exceptions that are caused by user input.Nr   r   r   r   r   r:   t   r   r:   c                       "   e Zd ZdZd fdd	Z  ZS )InvalidResourceExceptionz5A collection-path that was given could not be parsed.Nc                    s0   dj |d}|r|d| 7 }tt| | d S )Nz!could not parse resource [{line}]linez: )r    r   r<   r   )r!   r>   reasonmessager"   r   r   r   {   s   z!InvalidResourceException.__init__Nr%   r   r   r"   r   r<   x       r<   c                       r   ) WrongResourceCollectionExceptionz7A command line that was given had the wrong collection.c                    s,   t t| dj|||d || _|| _d S )NzGwrong collection: expected [{expected}], got [{got}], for path [{path}]expectedgotpath)r   rC   r   r    rF   rG   )r!   rE   rF   rG   r"   r   r   r      s   

z)WrongResourceCollectionException.__init__r%   r   r   r"   r   rC      r'   rC   c                       r   )RequiredFieldOmittedExceptionz6A command line that was given did not specify a field.c                    s   t t| dj||d d S )Nz_value for field [{expected}] in collection [{collection_name}] is required but was not provided)rE   collection_name)r   rH   r   r    )r!   rI   rE   r"   r   r   r      s   
z&RequiredFieldOmittedException.__init__r%   r   r   r"   r   rH      r'   rH   c                       r   )UnknownCollectionException;A command line that was given did not specify a collection.c                    r   )Nzunknown collection for [{line}]r=   )r   rJ   r   r    )r!   r>   r"   r   r   r      r$   z#UnknownCollectionException.__init__r%   r   r   r"   r   rJ      r'   rJ   c                       r;   )InvalidCollectionExceptionrK   Nc                    s4   dj |d}|r|dj |d7 }tt| | d S )Nz!unknown collection [{collection}]r   z for API version [{version}])version)r    r   rL   r   )r!   r   api_versionr@   r"   r   r   r      s   z#InvalidCollectionException.__init__rA   r%   r   r   r"   r   rL      rB   rL   c                   @   sB   e Zd ZdZdd Z	dddZ			dd
dZdd Zdd ZdS )_ResourceParserzFClass that turns command-line arguments into a cloud resource message.c                 C   s   || _ || _dS )zCreate a _ResourceParser for a given collection.

    Args:
      registry: Registry, The resource registry this parser belongs to.
      collection_info: resource_util.CollectionInfo, description for collection.
    N)registrycollection_info)r!   rP   rQ   r   r   r   r      s   
z_ResourceParser.__init__N Fc           	      C   s   t |}| j|}t||}|st|d| jj|| j	|}|
 }|r1ttjj|}t| j| j|tt|||dS )aF  Parse relative name into a Resource object.

    Args:
      relative_name: str, resource relative name.
      base_url: str, base url part of the api which manages this resource.
      subcollection: str, id of subcollection. See the api resource module
          (googlecloudsdk/generated_clients/apis/API_NAME/API_VERSION/resources.py).
      url_unescape: bool, if true relative name parameters will be unescaped.

    Returns:
      Resource representing this name.

    Raises:
      InvalidResourceException: if relative name doesn't match collection
          template.
    zBIt is not in {0} collection as it does not match path template {1})param_valuesendpoint_url)r   UniversifyAddressrQ   GetPathRegExrematchr<   r    	full_name	GetParamsgroupsr
   r   parseunquoteResourcerP   dictr   )	r!   relative_namebase_urlsubcollectionurl_unescapepath_templaterX   r2   fieldsr   r   r   ParseRelativeName   s"   
z!_ResourceParser.ParseRelativeNameTc                    s  t |} dur<z	| j ||dW S  ty;   | j|}| |}t fdd|D }	|	r8td	 	 Y nw | j
|}
t| |
s\td	t| t|
| jjt rtj | jj|d}|j}t|t|
krt |
|jr|jdddt|t|
k r|dgt|
t|  7 }t|}ndgt|
 } |d	< tt|
|}| D ]$\}}|durq||}|rt|r| n|||< q|r||||< qt| j | j|||}|S )
a  Given a command line and some keyword args, get the resource.

    Args:
      resource_id: str, Some identifier for the resource.
          Can be None to indicate all params should be taken from kwargs.
      kwargs: {str:(str or func()->str)}, flags (available from context) or
          resolvers that can help parse this resource. If the fields in
          collection-path do not provide all the necessary information,
          kwargs will be searched for what remains.
      base_url: use this base url (endpoint) for the resource, if not provided
          default corresponding api version base url will be used.
      subcollection: str, name of subcollection to use when parsing this path.
      validate: bool, Validate syntax. Use validate=False to handle IDs under
        construction. An ID can be:
          fully qualified - All parameters are specified and have valid syntax.
          partially qualified - Some parameters are specified, all have valid
            syntax.
          under construction - Some parameters may be missing or too short and
            not meet the syntax constraints. With additional characters they
            would have valid syntax. Used by completers that build IDs from
            strings character by character. Completers need to do the
            string => parameters => string round trip with validate=False to
            handle the "add character TAB" cycle.
      default_resolver: func(str) => str, a default param resolver function
        called if kwargs doesn't resolve a param.

    Returns:
      protorpc.messages.Message, The object containing info about this resource.

    Raises:
      InvalidResourceException: If the provided collection-path is malformed.
      WrongResourceCollectionException: If the collection-path specified the
          wrong collection.
      RequiredFieldOmittedException: If the collection-path's path did not
          provide enough fields.
      GRIPathMismatchException: If the number of path segments in the GRI does
          not match the expected format of the URL for the given resource
          collection.
      ValueError: if parameter set in kwargs is not subset of the resource
          parameters.
    Nra   rb   c                 3   s    | ]	}|d   v V  qdS )/Nr   ).0prefixresource_idr   r   	<genexpr>  s    
z2_ResourceParser.ParseResourceId.<locals>.<genexpr>zInvalid value: {}zPProvided params {} is not subset of the resource parameters {} for collection {}r   validater   )!r   rU   rf   r<   rQ   GetPathGetFieldNamesFromPathallr:   r    rZ   setkeysissubset
ValueErrorsortedrY   _GRIsAreEnabledGRI
FromStringpath_fieldslenGRIPathMismatchExceptionis_fully_qualifiedr   reversedr_   r   itemsgetcallabler^   rP   )r!   rl   kwargsra   rb   ro   default_resolverrG   path_prefixescontains_all_fieldsr2   grire   rS   r   valueresolverrefr   rk   r   ParseResourceId   sp   
,



z_ResourceParser.ParseResourceIdc                 C   s   dd t |dD S )zExtract field names from uri template path.

    Args:
      path: str, uri template path.

    Returns:
      list(str), list of field names in the template path.
    c                 S   s$   g | ]\}}|d  dkr|r|qS )   r   r   )ri   idxrj   r   r   r   
<listcomp>K  s
    z9_ResourceParser.GetFieldNamesFromPath.<locals>.<listcomp>rh   )	enumeratesplit)r!   rG   r   r   r   rr   B  s
   	z%_ResourceParser.GetFieldNamesFromPathc                 C   s2   d}| j jD ]	}dj||d}qdj| j j|dS )NrR   z[{path}]/{param})rG   r   z[{collection}::]{path})r   rG   )rQ   r2   r    rY   )r!   path_strr   r   r   r   __str__Q  s   z_ResourceParser.__str__)NrR   F)NrR   TN)	r   r   r   r   r   rf   r   rr   r   r   r   r   r   rO      s    
#
irO   c                       s   e Zd ZdZdd Z fddZdd Zdd	 Zd
d Zdd Z	d$ddZ
dd Zdd Zdd Zd%ddZdd Zdd Zdd Zd d! Zd"d# Z  ZS )&r^   z#Information about a Cloud resource.c                 C   s   || _ || _|r|| _nt|j| _|| _||| _|	|| _
t|D ]\}}|du r5t|j|t| || q'd| jt| j|  | _| jjdv rYtj| j| _d| _dS )a  Create a Resource object that may be partially resolved.

    To allow resolving of unknown params to happen after parse-time, the
    param resolution code is in this class rather than the _ResourceParser
    class.

    Args:
      registry: Registry, The resource registry this parser belongs to.
      collection_info: resource_util.CollectionInfo, The collection description
          for this resource.
      subcollection: str, id for subcollection of this collection.
      param_values: {param->value}, A list of values for parameters.
      endpoint_url: str, override service endpoint url for this resource. If
           None default base url of collection api will be used.
    Raises:
      RequiredFieldOmittedException: if param_values have None value.
    Nz{0}{1})computestoragecertificatemanagerT)	_registry_collection_info_endpoint_urlr   rU   ra   _subcollectionrq   _pathrZ   _paramssix	iteritemsrH   rY   setattrr    uritemplateexpandAsDict
_self_linkapi_namer   r\   r]   _initialized)r!   rP   rQ   rb   rS   rT   r   r   r   r   r   r   \  s(   
zResource.__init__c                    s4   t | dd d urtd|tt| || d S )Nr   z<Cannot set attribute {0}. Resource references are immutable.)getattrNotImplementedErrorr    r   r^   __setattr__)r!   keyr   r"   r   r   r     s   zResource.__setattr__c                 C   s   t d|)Nz?Cannot delete attribute {0}. Resource references are immutable.)r   r    )r!   r   r   r   r   __delattr__  s   zResource.__delattr__c                 C   s    | j j}| jr|d | j S |S )N.)r   rY   r   )r!   r   r   r   r   
Collection  s   zResource.Collectionc                 C      | j S rA   )r   r!   r   r   r   GetCollectionInfo     zResource.GetCollectionInfoc                 C   s   | j rt| | j d S d S )Nrp   )r   r   r   r   r   r   Name  s   zResource.NameFc                    sD   |rt jjndd  t fddjD }t jtj|S )aH  Relative resource name.

    A URI path ([path-noscheme](http://tools.ietf.org/html/rfc3986#appendix-A))
    without the leading "/". It identifies a resource within the API service.
    For example:
      "shelves/shelf1/books/book2"

    Args:
      url_escape: bool, if true would url escape each parameter.
    Returns:
       Unescaped part of SelfLink which is essentially base_url + relative_name.
       For example if SelfLink is
         https://pubsub.googleapis.com/v1/projects/myprj/topics/mytopic
       then relative name is
         projects/myprj/topics/mytopic.
    c                 S   s   | S rA   r   )xsafer   r   r   <lambda>  s    z'Resource.RelativeName.<locals>.<lambda>c                    s"   g | ]}| t |d dfqS )rR   )r   r   ri   kescape_funcr!   r   r   r     s    z)Resource.RelativeName.<locals>.<listcomp>)	r   r\   quoter_   r   r]   r   r   r   )r!   
url_escapeeffective_paramsr   r   r   RelativeName  s   zResource.RelativeNamec                    s   t  fdd jD S )z5Returns resource reference parameters and its values.c                    s   g | ]	}|t  |gqS r   r   ri   r   r   r   r   r     s    z#Resource.AsDict.<locals>.<listcomp>)collectionsOrderedDictr   r   r   r   r   r     s
   
zResource.AsDictc                    s    fdd j D S )z"Returns resource reference values.c                    s   g | ]}t  |qS r   r   r   r   r   r   r         z#Resource.AsList.<locals>.<listcomp>)r   r   r   r   r   AsList  s   zResource.AsListc                 C   r   )zReturns URI for this resource.r   r   r   r   r   SelfLink  s   zResource.SelfLinkNc           
         s   j dd } jj jj  jj }|r;z|| }W n ty&   t|w |j	d}||kr:t
  |||n@t|D ]\}}|j	d|krY|jd jv rY|} nq@|srt|D ]\}}|j	d|krq|} nqa|s{t  | fdd|D } jjd||d}	|	S )aC  Gets a reference to the parent of this resource.

    If parent_collection is not given, we attempt to automatically determine it
    by finding the collection within the same API that has the correct set of
    URI parameters for what we expect. If the parent collection cannot be
    automatically determined, it can be specified manually.

    Args:
      parent_collection: str, The full collection name of the parent resource.
        Only required if it cannot be automatically determined.

    Raises:
      ParentCollectionResolutionException: If the parent collection cannot be
        determined or doesn't exist.
      ParentCollectionMismatchException: If the given or auto-resolved parent
       collection does not have the expected URI parameters.

    Returns:
      Resource, The reference to the parent resource.
    Nrp   rR   c                    s   i | ]}|t  |qS r   r   r   r   r   r   
<dictcomp>  s    z#Resource.Parent.<locals>.<dictcomp>r   )r   r   parsers_by_collectionr   r   rN   KeyErrorrJ   rQ   rZ   r6   r   r   r   rq   r   r/   Parse)
r!   r7   parent_paramsall_collectionsparent_parseractual_parent_paramsr   parserparent_param_valuesr   r   r   r   Parent  sP   

zResource.Parentc                 C   r   rA   r   r   r   r   r   r   
  r   zResource.__str__c                 C   s   t |tr|  | kS dS NF)
isinstancer^   r   r!   otherr   r   r   __eq__  s   
zResource.__eq__c                 C   s   |   |  k S rA   )r   r   r   r   r   __lt__  s   zResource.__lt__c                 C   s
   t | jS rA   )hashr   r   r   r   r   __hash__  s   
zResource.__hash__c                 C   r   rA   r   r   r   r   r   __repr__  r   zResource.__repr__)FrA   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r&   r   r   r"   r   r^   Y  s$    ,

<r^   c                   C   s    t jjj pt jjj dkS )z!Returns True if GRIs are enabled.r   )r	   VALUEScore
enable_griGetBoolresource_completion_styleGetr   r   r   r   ry     s   ry   c                 C   s   |  dd S )zGet the API name from a collection name like 'api.parents.children'.

  Args:
    collection: str, The collection name.

  Returns:
    str: The API name.
  r   r   )r   r   r   r   r   _APINameFromCollection"  s   	r   c                   @   r   )GRIExceptionz*Base class for all GRI related exceptions.Nr   r   r   r   r   r   .  s    r   c                       r   )InvalidGRIFormatExceptionz2Exception for when a GRI is syntactically invalid.c                    r   )NzlThe given GRI [{gri}] is invalid and could not be parsed.
Valid GRIs take the form of: a:b:c::api.collection)r   )r   r   r   r    r!   r   r"   r   r   r   6  s
   
z"InvalidGRIFormatException.__init__r%   r   r   r"   r   r   3  r'   r   c                       r   )#InvalidGRICollectionSyntaxExceptionzLException for when the collection part of a GRI is syntactically invalid.
  c                       t t| dj||d d S )NzZThe given GRI [{gri}] could not be parsed because the collection [{collection}] is invalid)r   r   )r   r   r   r    )r!   r   r   r"   r   r   r   A  
   
z,InvalidGRICollectionSyntaxException.__init__r%   r   r   r"   r   r   =  r5   r   c                       r   )GRICollectionMismatchExceptionzLException for when the parsed GRI collection does not match the expected.
  c                    s    t t| dj|||d d S )NzThe given GRI [{gri}] could not be parsed because collection [{expected_collection}] was expected but [{parsed_collection}] was provided. Provide a GRI with the correct collection or drop the specified collection.)r   expected_collectionparsed_collection)r   r   r   r    )r!   r   r   r   r"   r   r   r   L  s   
z'GRICollectionMismatchException.__init__r%   r   r   r"   r   r   H  r5   r   c                       r   )InvalidGRIPathSyntaxExceptionzMException for when a part of the path of the GRI is syntactically invalid.
  c                    r   )NzPThe given GRI [{gri}] could not be parsed because the path is invalid: {message})r   r@   )r   r   r   r    )r!   r   r@   r"   r   r   r   [  r   z&InvalidGRIPathSyntaxException.__init__r%   r   r   r"   r   r   W  r5   r   c                       r;   )r~   z=Exception for when the path has the wrong number of segments.Nc                    s8   t t| dj|dt||rd| nd d d S )NzxThe given GRI [{gri}] does not match the required structure for this resource type. It must match the format: [{format}]:::rR   )r   r    )r   r~   r   r    r3   r   )r!   r   r2   r   r"   r   r   r   e  s   
z!GRIPathMismatchException.__init__rA   r%   r   r   r"   r   r~   b  rB   r~   c                   @   sn   e Zd ZdZdddZdd Zedd	d
ZedddZedd Z	edd Z
edd Zedd ZdS )rz   a}  Encapsulates a parsed GRI string.

  Attributes:
    path_fields: [str], The individual fields of the path portion of the GRI.
    collection: str, The collection portion of the GRI.
    is_fully_qualified: bool, True if the original GRI included the collection.
      This could be false if the collection is not defined, or if it was passed
      in explicitly during parsing.
  NFc                 C   s   || _ || _|o|du| _dS )z$Use FromString() to construct a GRI.N)r|   r   r   )r!   r|   r   r   r   r   r   r   y  s   zGRI.__init__c                    s8   d  fdd jD d} jr|d j 7 }|S )Nr   c                       g | ]}  |qS r   )_EscapePathSegment)ri   sr   r   r   r     s    zGRI.__str__.<locals>.<listcomp>r   )r3   r|   rstripr   r   r   r   r   r   r     s   zGRI.__str__Tc                 C   sb   | j ||d\}}|s|}n|r#| || |r#||kr#t|||d| |}t||t|dS )aB  Parses a GRI from a string.

    Args:
      gri: str, The GRI to parse.
      collection: str, The collection this GRI is for. If provided and the GRI
        contains a collection, they must match. If not provided, the collection
        in the GRI will be used, or None if it is not specified.
      validate: bool, Validate syntax. Use validate=False to handle GRIs under
        construction.

    Returns:
      A parsed GRI object.

    Raises:
      GRICollectionMismatchException: If the given collection does not match the
        collection specified in the GRI.
    )ro   )r   r   )r   )_SplitCollection_ValidateCollectionr   
_SplitPathrz   bool)clsr   r   ro   rG   r   r|   r   r   r   r{     s   

zGRI.FromStringc                 C   s   |sdS t d|}t|dkrt|t|dkr,|d |d }}|r+| || n|d d}}|rD|ds?|drDt|d||fS )	a  Splits a GRI into its path and collection segments.

    Args:
      gri: str, The GRI string to parse.
      validate: bool, Validate syntax. Use validate=False to handle GRIs under
        construction.

    Returns:
      (str, str), The path and collection parts of the string. The
      collection may be None if not specified in the GRI.

    Raises:
      InvalidGRIFormatException: If the GRI cannot be parsed.
      InvalidGRIPathSyntaxException: If the GRI path cannot be parsed.
    )NNz6(?=(?<={)::+[^:}]|(?<=[^:{])::+}|(?<=[^:{])::+[^:}])::r   r      Nr   z%GRIs cannot have empty path segments.)rW   r   r}   r   r   
startswithendswithr   )r   r   ro   partsrG   r   r   r   r   r     s$   zGRI._SplitCollectionc                 C   s   t d|st||d S )Nz^\w+\.\w+(?:\.\w+)*$)rW   rX   r   )r   r   r   r   r   r   r     s   
zGRI._ValidateCollectionc                    s&   |sg S t d|} fdd|D S )zSplits a GRI into its individual path segments.

    Args:
      path: str, The path segment of the GRI (from _SplitCollection)

    Returns:
      [str], A list of the path segments of the GRI.
    z2(?=(?<={):+[^:}]|(?<=[^:{]):+}|(?<=[^:{]):+[^:}]):c                    r   r   )_UnescapePathSegment)ri   partr   r   r   r     r   z"GRI._SplitPath.<locals>.<listcomp>)rW   r   )r   rG   r   r   r   r   r     s   
zGRI._SplitPathc                 C      t dd|S )Nz{(:+)}z\1rW   subr   segmentr   r   r   r        zGRI._UnescapePathSegmentc                 C   r   )Nz(:+)z{\1}r   r   r   r   r   r     r  zGRI._EscapePathSegmentr   )NT)T)r   r   r   r   r   r   classmethodr{   r   r   r   r   r   r   r   r   r   rz   n  s     

&,


rz   c                 C   s4   zt jj|  }W t|S  t jy   Y dS w )z5Check if a URL is the result of an endpoint override.F)r	   r   api_endpoint_overridesPropertyr   NoSuchPropertyErrorr   )r   endpoint_overrider   r   r   HasOverriddenEndpoint  s   r  c                   @   s   e Zd ZdZ		dddZdd Zd 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 ZdS )$Registrya  Keep a list of all the resource collections and their parsing functions.

  Attributes:
    parsers_by_collection: {str: {str: {str: _ResourceParser}}}, All the
        resource parsers indexed by their api name, api version
        and collection name.
    parsers_by_url: {str: {str: <Deeply-nested dict>}}, URL parsing tries
        indexed by api name and api version. Each key within a trie can be
        either a constant or a parameter name and represents a possible URL
        token after the API's base URL. At the end, a key of None indicates the
        value is a _ResourceParser.
    registered_apis: {str: str}, The most recently registered API version for
        each API. For instance, {'dns': 'v1', 'compute': 'alpha'}.
  Nc                 C   s"   |pi | _ |pi | _|pi | _d S rA   r   parsers_by_urlregistered_apis)r!   r   r
  r  r   r   r   r     s   

zRegistry.__init__c                 C   s   t | j| j| j dS )zClones this registry.

    Clones share the same underlying parser data and differ only in which API
    versions were most recently registered.

    Returns:
      Registry, The cloned registry.
    r	  )r  r   r
  r  copyr   r   r   r   Clone  s
   	zRegistry.Clonec                 C   sf   | j |d}|du r|r|}nt|}|| j|i vr,t||D ]}| | q$|| j |< |S )zRegister the given API if it has not been registered already.

    Args:
      api_name: str, The API name.
      api_version: str, The API version, None for the default version.
    Returns:
      api version which was registered.
    N)r  r   r   _GetDefaultVersionr   _GetApiCollections_RegisterCollection)r!   r   rN   registered_versionr   r   r   r   RegisterApiByName-  s   	

zRegistry.RegisterApiByNamec                 C   s   |j }|j}t| |}| j|i |i }|j}|s d|ji}t|D ]2\}}|j	|r1d| nd }	|
|	}
|
durGt|	|j|
jjg|||	< |jrW| ||||| q%dS )a?  Registers given collection with registry.

    Args:
      collection_info: CollectionInfo, description of resource collection.
    Raises:
      AmbiguousAPIException: If the API defines a collection that has already
          been added.
      AmbiguousResourcePath: If api uses same path for multiple resources.
    rR   r   N)r   rN   rO   r   
setdefault
flat_pathsrG   r   r   rY   r   r(   ra   rQ   enable_uri_parsing_AddParserForUriPath)r!   rQ   r   rN   r   collection_parserscollection_subpathssubnamerG   rI   existing_parserr   r   r   r  G  s2   



zRegistry._RegisterCollectionc           	      C   s   ||g| d }| j}|r/|d}|d dkr!|d dkr!d}||vr)i ||< || }|sd|v r<t|d |jj||f|d< dS )z Registers parser for given path.rh   r   {rp   }{}N)r   r
  popr,   rQ   name)	r!   r   rN   rb   r   rG   tokens	cur_leveltokenr   r   r   r  h  s   
zRegistry._AddParserForUriPathc                 C   sJ   t |}| j||d}| j|i |i |d}|du r#t|||S )a/  Returns a parser object for collection.

    Args:
      collection: str, The resource collection name.
      api_version: str, The API version, None for the default version.

    Raises:
      InvalidCollectionException: If there is no parser.

    Returns:
      The parser object for collection.
    rN   N)r   r  r   r   rL   )r!   r   rN   r   r   r   r   r   GetParserForCollection  s   
zRegistry.GetParserForCollectionTc                 C   s   t  rtj|||dj}|st|| j||d}t|jj|jj	}|jj
}	d}
t|	t|kr:|t|	d d }
|j||||
||dS )a  Parse a resource id string into a Resource.

    Args:
      collection: str, the name/id for the resource from commandline argument.
      resource_id: str, Some resource identifier.
          Can be None to indicate all params should be taken from kwargs.
      kwargs: {str:(str or func()->str)}, flags (available from context) or
          resolvers that can help parse this resource. If the fields in
          collection-path do not provide all the necessary information,
          kwargs will be searched for what remains.
      validate: bool, Validate syntax. Use validate=False to handle IDs under
        construction. An ID can be:
          fully qualified - All parameters are specified and have valid syntax.
          partially qualified - Some parameters are specified, all have valid
            syntax.
          under construction - Some parameters may be missing or too short and
            not meet the syntax constraints. With additional characters they
            would have valid syntax. Used by completers that build IDs from
            strings character by character. Completers need to do the
            string => parameters => string round trip with validate=False to
            handle the "add character TAB" cycle.
      api_version: str, The API version, None for the default version.
      default_resolver: func(str) => str, a default param resolver function
        called if kwargs doesn't resolve a param.

    Returns:
      protorpc.messages.Message, The object containing info about this resource.

    Raises:
      InvalidCollectionException: If the provided collection-path is malformed.
      UnknownCollectionException: If the collection of the resource could not be
          determined.

    rn   r#  rR   r   N)ro   r   )ry   rz   r{   r   rJ   r$  GetApiBaseUrlrQ   r   rN   rY   r}   r   )r!   r   rl   r   ro   rN   r   r   ra   parser_collectionrb   r   r   r   r     s(   $zRegistry.ParseResourceIdc                 C   sL   t |}| j||d}| j|i |i |d }|d u r#t|||jS )Nr#  )r   r  r   r   rL   rQ   )r!   rI   rN   r   r   r   r   r   r     s   
zRegistry.GetCollectionInfoc                 C   s  t |}|st|ddt|\}}}|p|}zt|}W n tjy0   t|d	|w ||vrCt
|rC| j|t|}||vrOt|d	|||g|d }|dt|  }	z	| j||d W n tjyz   t|d	| tjy   t|d	|w g }
| j}t|D ]V\}}||v r|| }qdi }}t|D ]
\}}|d	kr n
qt|d
	|dt|dkrd|v rd||d }|
tj| |} n|
tj| |}qd|vrt|d|d \}}tt|j||
}
|jd|
|	|dS )ac  Parse a URL into a Resource.

    Searches self.parsers_by_url to find a _ResourceParser. The parsers_by_url
    attribute is a deeply nested dictionary, indexed by API name, API version,
    then a series of keys corresponding to URL segments (split on '/') after the
    API's base URL. Each of these keys can be either a literal segment (e.g.
    "projects" in
    "https://compute.googleapis.com/compute/v1/projects/{projectsId}/..."), in
    which case it must match exactly, or a wildcard parameter ("{}"), in which
    case it can match any token. For the URL provided, the API name (and if
    unspecified, the API version) is extracted from the base URL, then a path
    down the tree is followed, branching at each remaining token in the URL. If
    there are no URL tokens left, and one of the keys at the current level is
    None, the None points to a _ResourceParser that can turn the collected
    params into a Resource.

    Args:
      url: str, The URL of the resource.
      api_version: str, The API client version to use for parsing. For
        channel-based versioned clients, this argument is not needed as it
        can always be inferred from the URL. For interface-based versioned
        clients (as of 2024), this argument can be used to explicitly specify a
        client version (since multiple clients can share the same URL API
        version). If not provided, defaults to the API version in the URL.

    Returns:
      Resource, The resource indicated by the provided URL.

    Raises:
      InvalidResourceException: If the provided URL could not be turned into
          a cloud resource.
    zunknown API host)r?   zunknown api {}zunknown api version {}rh   Nr#  rR   r  zCould not parse at [{}]r   zUrl too short.rg   ) _URL_RErX   r<   resource_utilSplitEndpointUrlr   _GetVersionsr   UnknownAPIErrorr    r  r  r   r  r   r}   r  UnknownVersionErrorr
  r   r   r   r3   appendr   r\   r]   r_   r   rQ   rZ   r   )r!   urlrN   rX   r   url_api_versionresource_pathversionsr   endpointr2   r!  ir"  r   
next_levelrb   r   r   r   r   ParseURL  sx   
!





zRegistry.ParseURLFc                 C   s<   | j ||d}t|jj|jj}|j|}|||||S )z:Parser relative names. See Resource.RelativeName() method.r#  )r$  r%  rQ   r   rN   GetSubcollectionrf   )r!   r`   r   rc   rN   r   ra   rb   r   r   r   rf   H  s   zRegistry.ParseRelativeNamec                 C   s   t |}|st|d|dr.|r|dkrtd||| jdd|d|dddS |r:|dkr:td||| jddd	|didS )
z;Parse gs://bucket/object_path into storage.v1 api resource.zNot a storage urlr   storage.objectsNr   bucketobjectr   rl   r   storage.bucketsr9  )_GCS_URL_RErX   r<   grouprC   r   )r!   r.  r   rX   r   r   r   ParseStorageURLS  s(   


zRegistry.ParseStorageURLc                 C   s2  |r| ds| drz| ||}W n ty }	 zd}
tt}tt}tt}| |rVz|t|d 	dd\}}
}}W n	 t
yM   |	w ||fdkrU nh| |rz%z|t|d 	dd\}}
}}W n	 t
yw   |	w ||fdkr W n= ty }	 z1|t|d }d|v r|	dd\}
}n| jddd	|id
W  Y d}	~	W  Y d}	~	S W Y d}	~	nd}	~	ww |
dur| jdd|
|dd
W  Y d}	~	S  d}	~	ww |r|r| |krt|| | d|S | dr| j||dS |r|dur|st|| j|||pi |||dS )a+  Parse a Cloud resource from a command line.

    Args:
      line: str, The argument provided on the command line.
      params: {str:(str or func()->str)}, flags (available from context) or
        resolvers that can help parse this resource. If the fields in
        collection-path do not provide all the necessary information, params
        will be searched for what remains.
      collection: str, The resource's collection, or None if it should be
        inferred from the line.
      enforce_collection: bool, fail unless parsed resource is of this
        specified collection, this is applicable only if line is URL.
      validate: bool, Validate syntax. Use validate=False to handle IDs under
        construction.
      default_resolver: func(str) => str, a default param resolver function
        called if params doesn't resolve a param.
      api_version: str, The API version, None for the default version.

    Returns:
      A resource object.

    Raises:
      InvalidResourceException: If the line is invalid.
      RequiredFieldOmittedException: If resource is underspecified.
      UnknownCollectionException: If no collection is provided or can be
          inferred.
      WrongResourceCollectionException: If the provided URL points into a
          collection other than the one specified.
    zhttps://zhttp://Nrh      )bor   r<  r9  r;  r7  r8  rD   zgs://r   )rN   ro   r   )r   r5  r<   r   rU   _GCS_URL_GCS_ALT_URL_GCS_ALT_URL_SHORTr}   r   rw   r   r   rC   r   r?  )r!   r>   r2   r   enforce_collectionro   r   rN   r   er9  gcs_urlgcs_alt_urlgcs_alt_url_shortbucket_prefixobject_prefix
objectpathr   r   r   r   h  s   



	)
zRegistry.Parsec                 K   s   | j d||dS )a  Create a Resource from known collection and params.

    Args:
      collection: str, The name of the collection the resource belongs to.
      **params: {str:str}, The values for each of the resource params.

    Returns:
      Resource, The constructed resource.
    Nr1   )r   r4   r   r   r   Create  s   
zRegistry.Create)NNNrA   )TNN)FN)NNTTNN)r   r   r   r   r   r  r  r  r  r$  r   r   r5  rf   r?  r   rN  r   r   r   r   r  	  s.    

!


;

m


^r  c                 C   s0   t tjj| d}d}|durt| | |}|S )a5  Determine base url to use for resources of given version from API endpoint override.

  If no override is set by the user, return None.

  Args:
    api_name: str, The API name.
    api_version: str, The API version.

  Returns:
    Base URL of the API namespace, with API version, None if no override set.
  N)r   r	   r   r  _GetApiBaseUrlr   )r   rN   endpoint_override_propertyra   r   r   r   r%    s   

r%  c                 C   s$   t | |}|du rtd| |S )al  Determine base url to use for resources of given version using current override endpoint for this resource name.

  If no override is found, raise an error.

  Args:
    api_name: str, The API name.
    api_version: str, The API version.

  Returns:
    Base URL of the API namespace, with API version.

  Raises:
    UserError: If override endpoint is not set.
  NzLgcloud config property {} needs to be set in api_endpoint_overrides section.)r%  r:   r    )r   rN   api_base_urlr   r   r   GetApiBaseUrlOrThrow  s   
rR  c                 C   s"   t | |}|du rt|| |S |S )a  Determine base url to use for resources of given version using current override endpoint for this resource name.

  If no override is found, returns the default base url, with API version.

  Args:
    api_name: str, The API name.
    api_version: str, The API version.
    default_base_url: str, The default API endpoint.

  Returns:
    Base URL of the API namespace, with API version.
  N)r%  rO  )r   rN   default_base_urlrQ  r   r   r   GetApiBaseUrlOrDefault  s   
rT  c                 C   sJ   | }|dur#t ||}t|\}}}|du r||d 7 }t |}|S )zXDetermine base url to use for resources of given API version from the supplied base url.Nrh   )r   _GetBaseUrlFromApir(  r)  rU   )ra   r   rN   rQ  client_base_url_url_versionr   r   r   rO    s   
rO  )?r   
__future__r   r   r   r   rW   googlecloudsdk.api_lib.utilr   r   r   r(  googlecloudsdk.corer   r	   r   	six.movesr
   r   r   r   _COLLECTION_SUB_REcompiler'  r    _METHOD_ID_REr=  rC  rD  rE  	Exceptionr   r   r   r(   r,   r/   r6   r:   r<   rC   rH   rJ   rL   r:  rO   r^   ry   r   r   r   r   r   r   r~   rz   r  r  REGISTRYr%  rR  rT  rO  r   r   r   r   <module>   s|   	


	


 0 D
    M