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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	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mZ ddlmZ ddl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 dS )zGBackend stuff for the calliope.cli module.

Not to be used by mortals.
    )absolute_import)division)unicode_literalsN)actions)arg_parsers)base)command_loading)display)
exceptions)parser_arguments)parser_errors)parser_extensions)
usage_text)handlers)log)metrics)textc                   @   s*   e Zd ZdZd	ddZdd Zdd ZdS )
_Notesz$Auto-generated NOTES section helper.Nc                 C   s.   g | _ |r| j |  d| _d S d| _d S )NTF)_notesappendrstrip
_paragraph)selfexplicit_notes r   </tmp/google-cloud-sdk/lib/googlecloudsdk/calliope/backend.py__init__2   s
   

z_Notes.__init__c                 C   s>   |s	|du rdS n| j rd| _ | jd | j|  dS )z7Adds a note line with preceding separator if not empty.NF )r   r   r   r   )r   liner   r   r   AddLine:   s   z_Notes.AddLinec                 C   s   | j r	d| j S dS )z.Returns the notes contents as a single string.
N)r   joinr   r   r   r   GetContentsD   s   z_Notes.GetContentsN)__name__
__module____qualname____doc__r   r   r#   r   r   r   r   r   /   s
    

r   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 Z
dd Zdd Zdd Zdd Zd9ddZdd Zdd Zdd  Zd:d"d#Z	d;d$d%Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd<d3d4Zd=d5d6Zd9d7d8ZdS )>CommandCommonzA base class for CommandGroup and Command.

  It is responsible for extracting arguments from the modules and does argument
  validation, since this is always the same for groups and commands.
  c           
      C   s@  |j | _ || _|d | _| jdd| _td| | j|d< || _d|| _	|| _
|| _|| j_
|| j_tdd |jD | _|r| rKd| j_| rY| jjd	u rYd| j_| rc| jjd	u rgd
| j_| rod| j_| rt| D ]\}}	| jj||	dd qzt| jdi | _| | jj | j ||d d	S )a  Create a new CommandCommon.

    Args:
      common_type: base._Common, The actual loaded user written command or group
        class.
      path: [str], A list of group names that got us down to this command group
        with respect to the CLI itself.  This path should be used for things
        like error reporting when a specific element in the tree needs to be
        referenced.
      release_track: base.ReleaseTrack, The release track (ga, beta, alpha,
        preview) that this command group is in.  This will apply to all commands
        under it.
      cli_generator: cli.CLILoader, The builder used to generate this CLI.
      parser_group: argparse.Parser, The parser that this command or group will
        live in.
      allow_positional_args: bool, True if this command can have positional
        arguments.
      parent_group: CommandGroup, The parent of this command or group. None if
        at the root.
    _-zLoaded Command Group: %s.c                 S   s   g | ]}|t jkqS r   )r   Group).0tr   r   r   
<listcomp>       z*CommandCommon.__init__.<locals>.<listcomp>TNF)preserve_existingdetailed_help)parser_groupallow_positional_args)!category_parent_groupnamereplacecli_namer   debug_pathr!   dotted_name_cli_generator_common_type_release_trackany__mro__is_groupIsHidden
_is_hiddenIsUniverseCompatible_universe_compatibleIsDefaultUniverseCompatible_default_universe_compatibleIsUnicodeSupported_is_unicode_supportedNoticessix	iteritems	AddNoticegetattrr4   _ExtractHelpStringsr(   _AssignParser)
r   common_typepathrelease_trackcli_generatorr5   r6   parent_grouptagmsgr   r   r   r   P   sD   


zCommandCommon.__init__c                 C   
   | j  S )z*Gets the notices of this command or group.)r@   rM   r"   r   r   r   rM         
zCommandCommon.Noticesc                 C   r[   )z0Gets the release track of this command or group.)r@   ReleaseTrackr"   r   r   r   r]      r\   zCommandCommon.ReleaseTrackc                 C   r[   )z0Gets the hidden status of this command or group.)r@   rE   r"   r   r   r   rE      r\   zCommandCommon.IsHiddenc                 C   r[   )z8Gets the auto generated status of this command or group.)r@   IsAutoGeneratedr"   r   r   r   r^      r\   zCommandCommon.IsAutoGeneratedc                 C   r[   )z=Gets the universe compatible status of this command or group.)r@   rG   r"   r   r   r   rG      r\   z"CommandCommon.IsUniverseCompatiblec                 C   r[   )zEGets the default universe compatible status of this command or group.)r@   rI   r"   r   r   r   rI      r\   z)CommandCommon.IsDefaultUniverseCompatiblec                 C   r[   )z;Gets the unicode supported status of this command or group.)r@   rK   r"   r   r   r   rK      r\   z CommandCommon.IsUnicodeSupportedc                 C   s   | j  S )z9Returns True if this is the root element in the CLI tree.)r8   r"   r   r   r   IsRoot   s   zCommandCommon.IsRootc                 C   s   |   r| S | j S )zGets the top group of this CLI.)r_   r8   _TopCLIElementr"   r   r   r   r`      s   
zCommandCommon._TopCLIElementc                    s  t |\| _| _d| jv rtdd| jd  | _| jr+| jds+|  jd7  _| 	 rmdd
t| 	   d }| jd}|rVt| j| _|t| | jd< | j| jkrd|  j|7  _n	| j| | j | _| j| _t| jdkr| jd  r| jd  s| jd  | jdd	  | _| jd
 dkr| jd	d
 | _g }|  j  r|  | 	 r|t| 	   |rd
|d   fdd}|| j| _| jds|| j| _| jd}|rtd|s	t| j| _|t|| jd< d	S d	S d	S d	S )a
  Extracts short help, long help and man page index from a docstring.

    Sets self.short_help, self.long_help and self.index_help and adds release
    track tags if needed.

    Args:
      docstring: The docstring from which short and long help are to be taken
    briefz\s r-   z

DESCRIPTION   r   Nr*   c                    s   t dd  | S )Nz^(\s*)z\1)resub)txtrY   r   r   
_InsertTag   s   z5CommandCommon._ExtractHelpStrings.<locals>._InsertTag#z^[ \n]*\{(description|index)\})r   ExtractHelpStrings
short_help	long_helpr4   re   rf   stripendswithrM   r!   sortedvaluesgetdicttextwrapdedent
index_helplenisupperlowerr]   help_tagr   extendkeys
startswithmatch)r   	docstringall_noticesdescriptiontagsri   r   rh   r   rR      sZ   	



z!CommandCommon._ExtractHelpStringsNc              	   C   s   |s| j d}t|}|  r|d ||  j |  }|rH|dt	
t|dd |d |D ]}|d|  |d q9| S )z;Returns the NOTES section with explicit and generated help.NOTESz]This command is an internal implementation detail and may change or disappear without notice.z{} also available:zThis variant iszThese variants arer   z  $ )r4   rr   r   rE   r   r]   	help_note#GetExistingAlternativeReleaseTracksformatr   	Pluralizerw   r#   )r   contentsnotes
alternates	alternater   r   r   GetNotesHelpSection
  s,   

z!CommandCommon.GetNotesHelpSectionc              
   C   s   |st j| jd| j| d| _n|j| j| j| jd| j| d| _d| _t	j
| j| | j|d| _| jjdt| dtjdd	 | jjd
t| d
dtjdd	 | jjdt| dddt ddd |   dS )a!  Assign a parser group to model this Command or CommandGroup.

    Args:
      parser_group: argparse._ArgumentGroup, the group that will model this
        command or group's arguments.
      allow_positional_args: bool, Whether to allow positional args for this
        group or not.
    F)r   add_helpprogcalliope_command)helpr   r   r   r   N)parser	is_globalrW   allow_positionalz-hTzPrint a summary help and exit.)actionis_replicatedr7   r   z--helpzDisplay detailed help.z
--documentrd   
ATTRIBUTESzTHIS TEXT SHOULD BE HIDDEN)r   r   nargsmetavartypehiddenr   )r   ArgumentParserrm   r>   _parser
add_parserr;   rl   _sub_parserr   ArgumentInterceptorr?   aiadd_argumentr   ShortHelpActionr   COMMONLY_USED_FLAGSRenderDocumentActionr   ArgDict_AcquireArgs)r   r5   r6   r   r   r   rS   $  s^   	
		
zCommandCommon._AssignParserc                 C   s&   | }|D ]}| |}|s dS qdS )a.  Determines if the given sub command path is valid from this node.

    Args:
      command_path: [str], The pieces of the command path.

    Returns:
      True, if the given path parts exist under this command or group node.
      False, if the sub path does not lead to a valid command or group.
    FTLoadSubElement)r   command_pathcurrentpartr   r   r   IsValidSubPathe  s   

zCommandCommon.IsValidSubPathc                 C   s   g S zGets all the sub elements of this group.

    Returns:
      set(str), The names of all sub groups or commands under this group.
    r   r"   r   r   r   AllSubElementsv  s   zCommandCommon.AllSubElementsFc                 C      dS )  Load all the sub groups and commands of this group.

    Args:
      recursive: bool, True to continue loading all sub groups, False, to just
        load the elements under the group.
      ignore_load_errors: bool, True to ignore command load failures. This
        should only be used when it is not critical that all data is returned,
        like for optimizations like static tab completion.

    Returns:
      int, The total number of elements loaded.
    r   r   )r   	recursiveignore_load_errorsr   r   r   LoadAllSubElements  s   z CommandCommon.LoadAllSubElementsc                 C   r   )  Load a specific sub group or command.

    Args:
      name: str, The name of the element to load.
      allow_empty: bool, True to allow creating this group as empty to start
        with.
      release_track_override: base.ReleaseTrack, Load the given sub-element
        under the given track instead of that of the parent. This should only be
        used when specifically creating the top level release track groups.

    Returns:
      _CommandCommon, The loaded sub element, or None if it did not exist.
    Nr   )r   r9   allow_emptyrelease_track_overrider   r   r   r     s   zCommandCommon.LoadSubElementc                 C   s*   | }|D ]}| |}|du r dS q|S )a  Load a specific sub group or command by path.

    If path is empty, returns the current element.

    Args:
      path: list of str, The names of the elements to load down the hierarchy.

    Returns:
      _CommandCommon, The loaded sub element, or None if it did not exist.
    Nr   )r   rU   currr   r   r   r   LoadSubElementByPath  s   
z"CommandCommon.LoadSubElementByPathc                 C   s   | j S r$   )r=   r"   r   r   r   GetPath  s   zCommandCommon.GetPathc                 C   s   t | | jS r$   )r   GetUsager   r"   r   r   r   r     s   zCommandCommon.GetUsagec                 C      i S r$   r   r"   r   r   r   GetSubCommandHelps     z CommandCommon.GetSubCommandHelpsc                 C   r   r$   r   r"   r   r   r   GetSubGroupHelps  r   zCommandCommon.GetSubGroupHelpsc              
   C   s2  | j | j | j | j | jr| jjjD ]	}| jj| q| jjjr[| jjs1| jt	
  | jjjjD ]#}z| jjjdi | W q7 t	jyZ   tdj| j|d dw | j D ]*}|jrfq`|jrjq`|jrnq`z| j| W q` tjy   tdj| j|jdw | jj| jjj dS dS )z>Calls the functions to register the arguments for this module.z-repeated concept in {command}: {concept_name}r9   )commandconcept_namez"repeated flag in {command}: {flag})r   flagNr   )r@   _Flagsr   Argsr8   	argumentsr   concept_handleradd_conceptsr   RuntimeHandler_all_concepts
AddConceptRepeatedConceptNamer   ArgumentExceptionr   r>   GetAllAvailableFlagsr   do_not_propagateis_requiredAddFlagActionFromAncestorsargparseArgumentErroroption_stringsdisplay_infoAddLowerDisplayInfo)r   argconcept_detailsr   r   r   r   r     sR   

zCommandCommon._AcquireArgsTc                    s0   | j j| j j } rr|S  fdd|D S )Nc                    s$   g | ]} s	|j ss|js|qS r   )r   	is_hiddenr/   finclude_globalinclude_hiddenr   r   r1     s    z6CommandCommon.GetAllAvailableFlags.<locals>.<listcomp>)r   	flag_argsancestor_flag_args)r   r   r   flagsr   r   r   r     s   z"CommandCommon.GetAllAvailableFlagsc                 C   s   | j j}|r|S dd |D S )Nc                 S   s   g | ]}|j s|qS r   )r   r   r   r   r   r1   	  r2   z2CommandCommon.GetSpecificFlags.<locals>.<listcomp>)r   r   )r   r   r   r   r   r   GetSpecificFlags  s   zCommandCommon.GetSpecificFlagsc           	      C   s   g }|   }|r|| | j|}|r@|  }tt|dd dD ]\}}||dd }|r?|	 s?|d
| q$|S )zGets the names for the command in other release tracks.

    Args:
      value: str, Optional value being parsed after the command.

    Returns:
      [str]: The names for the command in other release tracks.
    c                 S   s   | d j pdS )Nr   r   )prefix)xr   r   r   <lambda>  s    zCCommandCommon.GetExistingAlternativeReleaseTracks.<locals>.<lambda>)keyrd   Nrb   )r   r   r?   %ReplicateCommandPathForAllOtherTracksr`   rp   rN   rO   r   rE   r!   )	r   valueexisting_alternativesrU   r   top_elementr+   r   alternative_cmdr   r   r   r     s   	
z1CommandCommon.GetExistingAlternativeReleaseTracksr$   FFFN)TT)T)r%   r&   r'   r(   r   rM   r]   rE   r^   rG   rI   rK   r_   r`   rR   r   rS   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r)   I   s:    O
DA
	

7
r)   c                       s   e Zd ZdZ		d$ f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 Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Z  ZS )'CommandGroupz+A class to encapsulate a group of commands.NFc	              	      s  t j||||dd}	tt| j|	|||d||d || _i | _i | _i | _i | _	t
 | _t ||\}
}| | | j|
 | j	| d| j}| j |g }|D ]\}}}|rd|g| j	|< qV|g| j|< qV|s| js| j	st|  st d| j|   dS )a  Create a new command group.

    Args:
      impl_paths: [str], A list of file paths to the command implementation for
        this group.
      path: [str], A list of group names that got us down to this command group
        with respect to the CLI itself.  This path should be used for things
        like error reporting when a specific element in the tree needs to be
        referenced.
      release_track: base.ReleaseTrack, The release track (ga, beta, alpha,
        preview) that this command group is in.  This will apply to all commands
        under it.
      construction_id: str, A unique identifier for the CLILoader that is being
        constructed.
      cli_generator: cli.CLILoader, The builder used to generate this CLI.
      parser_group: the current argparse parser, or None if this is the root
        command group.  The root command group will allocate the initial top
        level argparse parser.
      parent_group: CommandGroup, The parent of this group. None if at the root.
      allow_empty: bool, True to allow creating this group as empty to start
        with.

    Raises:
      LayoutException: if the module has no sub groups or commands
    F)
is_commandrU   rV   rW   r6   r5   rX   r-   z&Group {0} has no subgroups or commandsN)r   LoadCommonTypesuperr   r   _construction_idgroupscommands_groups_to_load_commands_to_loadset_unloadable_elementsFindSubElements!_RemoveInitExtensionsFileIfNeededupdater!   r=   r?   GetModulesByParentrr   rB   _GetMappedSubmodulesLayoutExceptionr   r>   	SubParser)r   
impl_pathsrU   rV   construction_idrW   r5   rX   r   rT   group_infoscommand_infos
group_nameadded_modulesmodule_namemodule_is_commandmodule_impl_path	__class__r   r   r   *  sX   $






zCommandGroup.__init__c                 c   sX    d | jdt|  j d dd}| j D ]}|d |d r)|V  qdS )z<Yields registered modules (if any) under this command group.r-   rd   Nr,   r+   r   )	r!   r=   boolr]   r   r:   r?   
GetModulesr}   )r   module_pathmr   r   r   r     s   z!CommandGroup._GetMappedSubmodulesc                    sH   |j  fddt| j D  |j fddt| jD  dS )zCopies all the sub groups and commands from this group to the other.

    Args:
      other_group: CommandGroup, The other group to populate.
      ignore: set(str), Names of elements not to copy.
    c                       i | ]\}}| vr||qS r   r   r/   r9   r   ignorer   r   
<dictcomp>  
    z5CommandGroup.CopyAllSubElementsTo.<locals>.<dictcomp>c                    r  r   r   r  r  r   r   r    r  N)r   r   rN   rO   r   )r   other_groupr  r   r  r   CopyAllSubElementsTo  s   

z!CommandGroup.CopyAllSubElementsToc                 C   s    | j s| jjtj| d| _ | j S )zGets or creates the argparse sub parser for this group.

    Returns:
      The argparse subparser that children of this group should register with.
          If a sub parser has not been allocated, it is created now.
    )r   r   )r   r   add_subparsersr   CommandGroupActionr"   r   r   r   r     s
   zCommandGroup.SubParserc                 C   s   t | j t | j B S r   )r   r   r|   r   r"   r   r   r   r     s   zCommandGroup.AllSubElementsc                 C   s   t | |S )zDetermines if the given name is a valid sub group or command.

    Args:
      name: str, The name of the possible sub element.

    Returns:
      bool, True if the name is a valid sub element of this group.
    )r
  r   )r   r9   r   r   r   IsValidSubElement  s   	zCommandGroup.IsValidSubElementc                 C   sf   d}|   D ]*}z| |}|d7 }W n   d}|s"td|  Y |r0|r0||j||d7 }q|S )r   r   rd   NzError loading element %s)r   r   )r   r   r   warningr   )r   r   r   totalr9   elementr   r   r   r     s"   
zCommandGroup.LoadAllSubElementsc              
   C   s.  | dd}| j|d}|s| j|d}|r|S || jv r!dS d}zT|| jv rMt| j| | j|g |p8|  | j	| j
|  | |d}|| j|j< W |S || jv rut| j| | j|g |pa|  | j	| j
|  | d}|| j|j< W |S W |S  tjy } z| j| t| W Y d}~|S d}~ww )r   r,   r+   N)rX   r   )rX   )r:   r   rr   r   r   r   r   r=   r]   r   r?   r   r9   r   Commandr   #ReleaseTrackNotImplementedExceptionaddr   r<   )r   r9   r   r   existingr  er   r   r   r     sV   







	zCommandGroup.LoadSubElementc                 C      t dd | j D S )Nc                 s   s.    | ]}|j tj|j| |jd fV  qdS )	help_textr   rV   Nr;   r   HelpInforl   rE   r]   r/   itemr   r   r   	<genexpr>  s    	
z2CommandGroup.GetSubCommandHelps.<locals>.<genexpr>)rs   r   rq   r"   r   r   r   r        	zCommandGroup.GetSubCommandHelpsc                 C   r!  )Nc                 s   s0    | ]}|j tj|j| | d fV  qdS r"  r$  r&  r   r   r   r(  $  s    	
z0CommandGroup.GetSubGroupHelps.<locals>.<genexpr>)rs   r   rq   r"   r   r   r   r   #  r)  zCommandGroup.GetSubGroupHelpsc                 C   s(   | j r
| j || |  || dS )a,  Constructs and runs the Filter() method of all parent groups.

    This recurses up to the root group and then constructs each group and runs
    its Filter() method down the tree.

    Args:
      context: {}, The context dictionary that Filter() can modify.
      args: The argparse namespace.
    N)r8   RunGroupFilterr@   Filter)r   contextargsr   r   r   r*  0  s   
zCommandGroup.RunGroupFilterc                 C   s   t | |  S r$   )r   GetCategoricalUsage_GroupSubElementsByCategoryr"   r   r   r   r.  >  s   z CommandGroup.GetCategoricalUsagec                 C   
   t | S r$   )r   GetUncategorizedUsager"   r   r   r   r1  C     
z"CommandGroup.GetUncategorizedUsagec                 C   r0  r$   )r   GetHelpHintr"   r   r   r   r3  F  r2  zCommandGroup.GetHelpHintc                 C   s4   dd }|    i }|| j|d< || j|d< |S )zCReturns dictionary mapping each category to its set of subelements.c                 S   sL   t t}|  D ]}| s#|jr||j | q	|tj | q	|S )z4Returns dictionary mapping specific to element type.)	collectionsdefaultdictr   rq   rE   r7   r  r   UNCATEGORIZED_CATEGORY)elementscategorized_dictr  r   r   r   %_GroupSubElementsOfSameTypeByCategoryL  s   
zWCommandGroup._GroupSubElementsByCategory.<locals>._GroupSubElementsOfSameTypeByCategoryr   command_group)r   r   r   )r   r9  
categoriesr   r   r   r/  I  s   z(CommandGroup._GroupSubElementsByCategoryc                 C   s   d}||v r| | dS dS )a  Removes _init_extensions.py file from command_infos dict if present.

    It prevents loading _init_extensions.py as a command file.
    This additional file is used by CLI Autogen to extend the functionality of
    an __init__.py file by allowing to add no-auto-generated custom code.

    Args:
      command_infos: dict, A dictionary of command names to a list of file paths
        that implement that command.
    _init_extensionsN)pop)r   r  init_extensions_filer   r   r   r   `  s   z.CommandGroup._RemoveInitExtensionsFileIfNeeded)NFr   r   )r%   r&   r'   r(   r   r   r  r   r   r  r   r   r   r   r*  r.  r1  r3  r/  r   __classcell__r   r   r  r   r   '  s*    
V

 
9r   c                       s,   e Zd ZdZ	d fdd	Zdd Z  ZS )r  zAA class that encapsulates the configuration for a single command.Nc           	   	      sL   t j||||d|jd}tt| j||||d||d | jj| | jd dS )am  Create a new command.

    Args:
      impl_paths: [str], A list of file paths to the command implementation for
        this command.
      path: [str], A list of group names that got us down to this command with
        respect to the CLI itself.  This path should be used for things like
        error reporting when a specific element in the tree needs to be
        referenced.
      release_track: base.ReleaseTrack, The release track (ga, beta, alpha,
        preview) that this command group is in.  This will apply to all commands
        under it.
      construction_id: str, A unique identifier for the CLILoader that is being
        constructed.
      cli_generator: cli.CLILoader, The builder used to generate this CLI.
      parser_group: argparse.Parser, The parser to be used for this command.
      parent_group: CommandGroup, The parent of this command.
    T)r   yaml_command_translatorr   )r   r   N)	r   r   r@  r   r  r   r   set_defaultsr=   )	r   r   rU   rV   r   rW   r5   rX   rT   r  r   r   r   s  s$   

zCommand.__init__c                 C   s   t   i }| jr| j|| | j||d}t| j| ||}t	j
|||| jjd }t   |jdkr@tj|jd|S )a  Run this command with the given arguments.

    Args:
      cli: The cli.CLI object for this command line tool.
      args: The arguments for this command as a namespace.

    Returns:
      The object returned by the module's Run() function.

    Raises:
      exceptions.Error: if thrown by the Run() function.
      exceptions.ExitCodeNoError: if the command is returning with a non-zero
        exit code.
    )clir,  )r   r   )	exit_code)r   Loadedr8   r*  r@   r   
LogCommandr>   Runr	   	Displayerr   r   DisplayRanrC  r
   ExitCodeNoError)r   rB  r-  tool_contextcommand_instance	resourcesr   r   r   rF    s    

zCommand.Runr$   )r%   r&   r'   r(   r   rF  r?  r   r   r  r   r  p  s
    
0r  )!r(   
__future__r   r   r   r   r4  re   rt   googlecloudsdk.callioper   r   r   r   r	   r
   r   r   r   r    googlecloudsdk.calliope.conceptsr   googlecloudsdk.corer   r   googlecloudsdk.core.utilr   rN   objectr   r)   r   r  r   r   r   r   <module>   s@      a  K