
    cQ                        d 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	mZ dd
lmZ ddlZej                   j#                         D  cg c]  } ej%                  |        c} Z G d de
j(                        Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d d e      Z G d! d" ej@                  ejB                              Z" G d# d$e#      Z$ G d% d&e#      Z% G d' d(e%      Z&yc c} w ))z4Utility for retrieving and parsing the Resource Map.    )absolute_import)division)unicode_literalsN)base)
exceptions)yaml)yaml_validator)filesc                       e Zd ZdZy)ResourceMapErrorzGeneral Purpose Exception.N)__name__
__module____qualname____doc__     8lib/googlecloudsdk/command_lib/util/resource_map/base.pyr   r   #   s    "r   r   c                   "     e Zd ZdZ fdZ xZS )ResourceMapInitializationErrorzGException for when an error occurs while initializing the resource map.c                 J    t         t        |   dj                  |             y )Nz+Error while initializing resource map: [{}])superr   __init__format)self
init_error	__class__s     r   r   z'ResourceMapInitializationError.__init__*   s&    	
(
;;A6*;MOr   r   r   r   r   r   __classcell__r   s   @r   r   r   '   s    OO Or   r   c                   "     e Zd ZdZ fdZ xZS )PrivateAttributeNotFoundErrorzFException for when a private attribute that doesn't exist is accessed.c                 L    t         t        |   dj                  ||             y )Nz*[{}] does not have private attribute [{}].)r   r!   r   r   )r   data_wrapperattribute_namer   s      r   r   z&PrivateAttributeNotFoundError.__init__3   s)    	
'
ELLN, -r   r   r   s   @r   r!   r!   0   s    N- -r   r!   c                   "     e Zd ZdZ fdZ xZS )ApiNotFoundErrorz<Exception for when an API does not exist in the ResourceMap.c                 J    t         t        |   dj                  |             y )Nz"[{}] API not found in ResourceMap.)r   r&   r   r   r   api_namer   s     r   r   zApiNotFoundError.__init__<   s"    	

=DDXNOr   r   r   s   @r   r&   r&   9   s    DP Pr   r&   c                   "     e Zd ZdZ fdZ xZS )ApiAlreadyExistsErrorzHException for when an API being added already exists in the ResourceMap.c                 J    t         t        |   dj                  |             y Nz'[{}] API already exists in ResourceMap.)r   r+   r   r   r(   s     r   r   zApiAlreadyExistsError.__init__D   s"    	
/188BDr   r   r   s   @r   r+   r+   A   s    PD Dr   r+   c                   "     e Zd ZdZ fdZ xZS )ResourceNotFoundErrorz8Exception for when a Resource does not exist in the API.c                 J    t         t        |   dj                  |             y )Nz'[{}] resource not found in ResourceMap.)r   r/   r   r   )r   resource_namer   s     r   r   zResourceNotFoundError.__init__L   s"    	
/188GIr   r   r   s   @r   r/   r/   I   s    @I Ir   r/   c                   "     e Zd ZdZ fdZ xZS )ResourceAlreadyExistsErrorzLException for when a Resource being added already exists in the ResourceMap.c                 J    t         t        |   dj                  |             y r-   )r   r3   r   r   r(   s     r   r   z#ResourceAlreadyExistsError.__init__T   s"    	
$d4188BDr   r   r   s   @r   r3   r3   Q   s    TD Dr   r3   c                   "     e Zd ZdZ fdZ xZS )MetadataNotFoundErrorCException for when a metadata field does not exist in the Resource.c                 L    t         t        |   dj                  ||             y )Nz/[{}] metadata field not found in [{}] Resource.)r   r6   r   r   r   r1   metadata_fieldr   s      r   r   zMetadataNotFoundError.__init__\   s&    	
/9@@M	+,r   r   r   s   @r   r6   r6   Y       K, ,r   r6   c                   "     e Zd ZdZ fdZ xZS )#TrackLevelResourceReleaseTrackErrorzGException for when an attempt to access a releast track of a RT occurs.c                 L    t         t        |   dj                  ||             y )Nz?Attempted accessing of [{}] track of TrackLevelResourceData[{}])r   r=   r   r   )r   attempted_rtaccessed_rtr   s      r   r   z,TrackLevelResourceReleaseTrackError.__init__e   s(    	
-
#VL+>@r   r   r   s   @r   r=   r=   b   s    O@ @r   r=   c                   "     e Zd ZdZ fdZ xZS )MetadataAlreadyExistsErrorr7   c                 L    t         t        |   dj                  ||             y )Nz.[{}] metadata already exists in [{}] Resource.)r   rB   r   r   r9   s      r   r   z#MetadataAlreadyExistsError.__init__o   s&    	
$d48??M	+,r   r   r   s   @r   rB   rB   l   r;   r   rB   c                   "     e Zd ZdZ fdZ xZS )UnwrappedDataExceptionz6Exception for when unwrapped data is added to the map.c                 L    t         t        |   dj                  ||             y )NzhThe following data must be wrapped in a(n) {}Data wrapper prior to being added to the resource map: [{}])r   rE   r   r   )r   
field_typedatar   s      r   r   zUnwrappedDataException.__init__x   s$    	
 $0	0	
D	!#r   r   r   s   @r   rE   rE   u   s    ># #r   rE   c                       e Zd ZdZd Zd Zd Zd Zd Ze	j                  d        Zd Zdd
Zd Zd Zd Zd Zd Zd Zd ZddZy	)ResourceMapBasea  Base data wrapper class for Resource Map metadata yaml files.

  This object loads the relevant resource map file upon instantiation and sets
  the parsed dictionary as the internal attribute _resource_map_data. Underlying
  dictionary data is never interacted with directly, and is instead is
  set/retrieved/interacted with via an ApiData wrapper object.

  Attributes:
    _resource_map_data: Dict containing metadata for each resource in each api.
  c                 n    d | _         d | _        | j                          i | _        | j	                          y N)_map_file_path_schema_file_path_register_paths_resource_map_data_load_resource_mapr   s    r   r   zResourceMapBase.__init__   s2    D!D Dr   c                 ^    |j                  d      rt        d|      | j                  |      S )z5Returns underlying API data when accessing attribute._ResourceMap)
startswithr!   get_apir   r)   s     r   __getattr__zResourceMapBase.__getattr__   s,    3)-BB<<!!r   c                     || j                   v S )z;Returns True if api_name exists in self._resource_map_data.rP   rX   s     r   __contains__zResourceMapBase.__contains__   s    t....r   c              #   v   K   t        j                  | j                        D ]  \  }}t        ||        yw)zBYields ApiData wrapper objects for each API in _resource_map_data.N)six	iteritemsrP   ApiDatar   r)   api_datas      r   __iter__zResourceMapBase.__iter__   s2     !mmD,C,CD(Hh'' Es   79c                 D    | j                         |j                         k(  S rL   to_dictr   others     r   __eq__zResourceMapBase.__eq__       <<>U]]_,,r   c                      y)zMust be overridden by child classes to register map and schema paths.

    Must explicitly set self._map_file_path and self._schema_file_path to
    appropriate filepaths in the overridden method of the child class.
    Nr   rR   s    r   rO   zResourceMapBase._register_paths   s     	r   c                    	 t        j                  | j                        5 }t        j                  |      | _        ddd       | j
                  si | _        yy# 1 sw Y   xY w# t         j                  $ r}t        |      d}~ww xY w)z@Loads the ~/resource_map.yaml file into self._resource_map_data.N)r
   
FileReaderrM   r   loadrP   MissingFileErrorr   )r   ferrs      r   rQ   z"ResourceMapBase._load_resource_map   ss    0D//0A"&))A, 1$$"$ % 10 !! 0*3//0s-   A% AA% A"A% %B8BBNc                 L   	 |r| j                          |r| j                          t        j                  |xs | j                        5 }t        j                  | j                  |       ddd       y# 1 sw Y   yxY w# t        j                  $ r}t        |      d}~ww xY w)zBPrunes and exports self._resource_map_data to ~/resource_map.yaml.)streamN)
prune_validate_resource_mapr
   
FileWriterrM   r   dumprP   ro   r   )r   	file_pathrt   validaterp   rq   s         r   _export_resource_mapz$ResourceMapBase._export_resource_map   s}    0	

	##%I<)<)<=		$))!4 >==!! 0*3//0s6   AB  	"A4+B  4A=9B  =B   B#BB#c                 t    t        j                  | j                        j                  | j                         y)z:Validates resource map against ~/resource_map_schema.yaml.N)r	   	ValidatorrN   ValidaterP   rR   s    r   ru   z&ResourceMapBase._validate_resource_map   s*    T334==!r   c                     | j                   S rL   r[   rR   s    r   rf   zResourceMapBase.to_dict   s    """r   c                 D    t        |       D ]  }|j                           y)a  Prunes the resource map, removing redundant metadata values in the map.

    Calls prune() on each ApiData wrapper object, which in turn calls prune()
    on each underlying resource. Pruning each resource will remove any instances
    of a track-specific metadata field being set to the same value as the parent
    resource metadata field, eliminating any redundancies and keeping the map
    as clean as possible.
    Niterrt   r   rb   s     r   rt   zResourceMapBase.prune   s     Jnn r   c                 f    || j                   vrt        |      t        || j                   |         S )z2Returns the api data wrapped in an ApiData object.)rP   r&   r`   rX   s     r   rW   zResourceMapBase.get_api   s3    t...X&&8T44X>??r   c                     t        |t              st        d|      |j                         | j                  v rt        |j                               | j                  j                  |j                                y)aH  Adds an api to the resource map.

    Args:
      api_data: Data for api being added. Must be wrapped in an ApiData object.

    Raises:
      ApiAlreadyExistsError: API already exists in resource map.
      UnwrappedDataException: API data attempting to be added without being
        wrapped in an ApiData wrapper object.
    ApiN)
isinstancer`   rE   get_api_namerP   r+   updaterf   r   s     r   add_apizResourceMapBase.add_api   sc     h("5(33				 D$;$;	;!("7"7"9::
$$X%5%5%78r   c                     t        |t              st        d|      |j                         | j                  vrt        |j                               | j                  j                  |j                                y)a`  Updates an API's data with the provided api data.

    Args:
      api_data: API Data to update the api with. Must be provided as an ApiData
      object.

    Raises:
      ApiNotFoundError: Api to be updated does not exist.
      UnwrappedDataException: API data attempting to be added without being
        wrapped in an ApiData wrapper object.
    r   N)r   r`   rE   r   rP   r&   r   rf   r   s     r   
update_apizResourceMapBase.update_api   sc     h("5(33d&=&==X22455
$$X%5%5%78r   c                 P    || j                   vrt        |      | j                   |= y)z%Removes an API from the resource map.N)rP   r&   rX   s     r   
remove_apizResourceMapBase.remove_api  s)    t...X&&)r   c                 &    | j                  |       y)z-Public method to export resource map to file.N)rz   )r   rx   s     r   exportzResourceMapBase.export	  s    i(r   )NFTrL   )r   r   r   r   r   rY   r\   rc   ri   abcabstractmethodrO   rQ   rz   ru   rf   rt   rW   r   r   r   r   r   r   r   rJ   rJ      sm    	"/(
- 	 	0
0!
#@9$9&*)r   rJ   c                   f    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd ZddZd Zy)r`   zData wrapper for an API object in the Resource Map metadata file.

  Attributes:
    _api_name: Name of the API.
    _api_data: Dict of resources and associated metadata constituting the api.
  c                      || _         || _        y rL   )	_api_name	_api_datara   s      r   r   zApiData.__init__  s    DNDNr   c                     |j                  d      rt        d|      t        || j                  | j                  |         S )zGReturns the specified resource's data wrapped in a ResourceData object.rT   r`   )rV   r!   ResourceDatar   r   r   r1   s     r   rY   zApiData.__getattr__  s>    $))]CCt~~}57 7r   c                     || j                   v S rL   )r   r   s     r   r\   zApiData.__contains__!  s    DNN**r   c              #      K   | j                   j                         D ]  \  }}t        || j                  |         yw)zGYields ResourceData wrapper objects for each API in _resource_map_data.N)r   itemsr   r   )r   r1   resource_datas      r   rc   zApiData.__iter__$  s5     (,(<(<(>$}FF )?s   =?c                 ,    t        | j                        S rL   )reprr   rR   s    r   __repr__zApiData.__repr__)  s    r   c                 D    | j                         |j                         k(  S rL   re   rg   s     r   ri   zApiData.__eq__,  rj   r   c                 H    t        j                  | j                               S rL   )r^   	text_typerf   rR   s    r   to_strzApiData.to_str/  s    ==((r   c                 :    | j                         | j                  iS rL   )r   r   rR   s    r   rf   zApiData.to_dict2  s    00r   c                 @    t        j                  | j                        S rL   )r^   r   r   rR   s    r   r   zApiData.get_api_name5  s    ==((r   c                 |    || j                   vrt        |      t        || j                  | j                   |         S )zEReturns the data for the specified resource in a ResourceData object.)r   r/   r   r   r   s     r   get_resourcezApiData.get_resource8  s:    DNN*!-00t~~}57 7r   c                     t        |t              st        d|      |j                         | j                  v rt        |j                               | j                  j                  |j                                y NResource)r   r   rE   get_resource_namer   r3   r   rf   r   r   s     r   add_resourcezApiData.add_resource?  s]    m\2":}==		(	(	*dnn	<&}'F'F'HII
nnM1134r   c                     t        |t              st        d|      |j                         | j                  vrt        |j                               | j                  j                  |j                                y r   )r   r   rE   r   r   r/   r   rf   r   s     r   update_resourcezApiData.update_resourceG  s]    m\2":}==		(	(	*$..	@!-"A"A"CDD
nnM1134r   c                 T    |r|| j                   vrt        |      | j                   |= y rL   )r   r/   )r   r1   
must_exists      r   remove_resourcezApiData.remove_resourceO  s'    m4>>9!-00}%r   c                 D    t        |       D ]  }|j                           y rL   r   r   s     r   rt   zApiData.pruneT  s    d $r   N)T)r   r   r   r   r   rY   r\   rc   r   ri   r   rf   r   r   r   r   r   rt   r   r   r   r`   r`     sN    7+G
 -)1)755&
r   r`   c                   |     e Zd ZdZd Zd Z fdZd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd Z xZS )r   zData wrapper for a Resource object in the ResourceMap metadata file.

  Attributes:
    _resource_name: Name of the resource.
    _api_name: Name of the parent api.
    _resource_data: Metadata for the resource.
  c                 .    || _         || _        || _        y rL   )_resource_namer   _resource_data)r   r1   r)   r   s       r   r   zResourceData.__init__b  s    'DDN'Dr   c                     |t         v r| j                  |      S |j                  d      rt        d|      | j	                  |      S )aI  Returns metadata value or TrackLevelResourceData object.

    Attribute being accessed will be either a metadata field for the resource,
    or the release track (GA, BETA, or ALPHA). If the attribute is a metadata
    field the appropriate value will be returned from self._resource_data. If
    the atatribute is a release track, a TrackLevelResourceData object will be
    returned. This enables both of the following usecases:

      `value = map.api.resource.metadata_field` OR
      'value = map.api.resource.ALPHA.metadata_field`

    Args:
      metadata_field: Field or release track being accessed

    Returns:
      Metadata field value OR TrackLevelResourceData object.

    Raises:
      MetadataNotFoundError: Metadata field does not exist.
      PrivateAttributeNotFoundError: Private attribute doesn't exist in object.

    rT   r   )_RELEASE_TRACKSget_release_track_datarV   r!   get_metadatar   r:   s     r   rY   zResourceData.__getattr__g  sI    . (((88		"	"3	')..II~..r   c                     |j                  d      rt        t        |   ||       y|| j                  vr| j                  ||       y| j                  ||       y)a  Sets the specified metadata field to the provided value.

    If the object is not yet instantiated, then standard __setattr__ behavior
    is observed, allowing for proper object instantiation. After initialization,
    the specified metadata field within self._resource_data is set to the
    provided value

    Args:
      metadata_field: Metadata field to set the value for.
      value: Value to set the specified metadata field to.

    Returns:
      True
    rT   N)rV   r   r   __setattr__r   add_metadataupdate_metadatar   r:   valuer   s      r   r   zResourceData.__setattr__  sR        %L$+NEB	t22	2
.
>51r   c                 D    | j                         |j                         k(  S rL   re   rg   s     r   ri   zResourceData.__eq__  rj   r   c                 $    | j                  |      S rL   )has_metadata_fieldr   s     r   r\   zResourceData.__contains__  s    "">22r   c                    t         D ]v  }|| j                  v s| j                  |   }t        |j                               D ]*  }|| j                  v s| j                  |   ||   k(  s(||= , |rj| j                  |= x y)zDRemoves any redundant metadata specifications between track and top.N)r   r   listkeys)r   tracktrack_resource_datakeys       r   rt   zResourceData.prune  s     	$%%	%"11%8+0023CD'''D,?,?-)#.-/#C( 4
 #!!%( !r   c                 :    | j                         | j                  iS rL   )r   r   rR   s    r   rf   zResourceData.to_dict  s    ""$d&9&9::r   c                     || j                   v S rL   )r   r   s     r   r   zResourceData.has_metadata_field  s    T0000r   c                     | j                   S rL   )r   rR   s    r   r   zResourceData.get_resource_name  s    r   c                     | j                   S rL   )r   rR   s    r   r   zResourceData.get_api_name  s    >>r   c                 ^    dj                  | j                         | j                               S )Nz{}.{})r   r   r   rR   s    r   get_full_collection_namez%ResourceData.get_full_collection_name  s%    >>$++-t/E/E/GHHr   c                 h    || j                   vrt        | j                  |      | j                   |   S rL   r   r6   r   r   s     r   r   zResourceData.get_metadata  s4    T000!$"5"5~FF~..r   c                 \    t        | j                  | j                  | j                  |      S )Nr   )TrackLevelResourceDatar   r   r   r   release_tracks     r   r   z#ResourceData.get_release_track_data  s+    !	 r   c                 j    || j                   v rt        | j                  |      || j                   |<   y rL   )r   rB   r   r   r:   r   s      r   r   zResourceData.add_metadata  s3    ,,,&t':':NKK,1d.)r   c                 j    || j                   vrt        | j                  |      || j                   |<   y rL   r   r   s      r   r   zResourceData.update_metadata  s3    T000!$"5"5~FF,1d.)r   c                 f    || j                   vrt        | j                  |      | j                   |= y rL   r   r   s     r   remove_metadatazResourceData.remove_metadata  s1    T000!$"5"5~FF


n
-r   )r   r   r   r   r   rY   r   ri   r\   rt   rf   r   r   r   r   r   r   r   r   r   r   r   s   @r   r   r   Y  sY    (
/<2.-3);1I/
22.r   r   c                   \     e Zd ZdZ fdZd Z fdZd Zd Zd Z	d Z
d	 Zd
 Zd Z xZS )r   a-  Data wrapper for track-specific resource metadata.

  This data wrapper represents the metadata for a specific release track of a
  resource. Retrieval of metadata will first check for a track level
  specification of the metadata, and if not found will then retrieve the
  top level metadata value.

  Attributes:
    _resource_name: Name of the resource.
    _api_name: Name of the parent api.
    _resource_data: Metadata for the resource.
    _track: Release track for the resource.
    _track_resource_data: Track specific metadata for the resource.
  c                     || _         |j                  | j                   i       | _        t        t        |   |||       y rL   )_trackget_track_resource_datar   r   r   )r   r1   r)   r   r   r   s        r   r   zTrackLevelResourceData.__init__  s;    DK - 1 1$++r BD	
 $01>@r   c                 ^    |j                  d      rt        d|      | j                  |      S )aR  Retrieves the track-specific metadata value for the resource.

    If the specified release track does not have a specified value, the parent
    metadata field value for the resource will be returned.

    Args:
      metadata_field: Metadata field value to retrieve

    Returns:
      Metadata field value for the specified release track-specific or the
      parent metadata field.

    Raises:
      MetadataNotFoundError: Metadata field value wasn't found for the specific
      track or for the parent.
      PrivateAttributeNotFoundError: Private attribute doesn't exist in object.
    rT   r   )rV   r!   r   r   s     r   rY   z"TrackLevelResourceData.__getattr__  s8    $   %)*B*8: : ~..r   c                     |j                  d      rt        t        |   ||       y|| j                  v r| j                  ||      S | j                  ||      S )a  Sets the specified metadata field to the provided value.

    If the object is not yet instantiated, then standard __setattr__ behavior
    is observed, allowing for proper object intitialization. After
    initialization, the specified metadata field for the release track is set
    to the provided value.

    Args:
      metadata_field: Metadata field to set the value for.
      value: Value to set the specified metadata field to.

    Returns:
      True
    rT   N)rV   r   r   r   r   r   r   r   s      r   r   z"TrackLevelResourceData.__setattr__  sY        %"D5neL	444	4##NE::  77r   c                 2    | j                   | j                  iS rL   )r   r   rR   s    r   rf   zTrackLevelResourceData.to_dict$  s    !4!455r   c                     || j                   v r| j                   |   S || j                  v r| j                  |   S t        | j                  |      rL   )r   r   r6   r   r   s     r   r   z#TrackLevelResourceData.get_metadata'  sS    222&&~66	4..	.  00!$"5"5~FFr   c                 j    || j                   v rt        | j                  |      || j                   |<   y rL   )r   rB   r   r   s      r   r   z#TrackLevelResourceData.add_metadata/  s3    222&t':':NKK27d/r   c                 j    || j                   vrt        | j                  |      || j                   |<   y rL   r   r6   r   r   s      r   r   z&TrackLevelResourceData.update_metadata5  s3    T666!$"5"5~FF27d/r   c                 f    || j                   vrt        | j                  |      | j                   |= y rL   r   r   s     r   r   z&TrackLevelResourceData.remove_metadata;  s1    T666!$"5"5~FF

#
#N
3r   c                     | j                   S rL   )r   rR   s    r   get_release_trackz(TrackLevelResourceData.get_release_trackA  s    ;;r   c                 .    t        || j                        rL   )r=   r   r   s     r   r   z-TrackLevelResourceData.get_release_track_dataD  s    
-mT[[
IIr   )r   r   r   r   r   rY   r   rf   r   r   r   r   r   r   r   r   s   @r   r   r     s=    @/0806G884Jr   r   )'r   
__future__r   r   r   r   googlecloudsdk.callioper   calliope_basegooglecloudsdk.corer   r   r	   googlecloudsdk.core.utilr
   r^   ReleaseTrack	AllValuesr   r   Errorr   r   r!   r&   r+   r/   r3   r6   r=   rB   rE   with_metaclassABCMetarJ   objectr`   r   r   r   s   0r   <module>r      sQ   ; &  ' 
 9 * $ . * 
 '4&@&@&J&J&L&LUCMM%&L
#z'' #O%5 O-$4 -P' PD, DI, ID!1 D,, ,@*: @,!1 ,#- #L)(c((5 L)^Hf HVB.6 B.JgJ\ gJAs   D<