
    F                        S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSKrSSK	r	SSK
r
SSKJr  SSKJr  SSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  SSKrSSSS0 SSS.rS/r " S S\5      rS rS\ 4S jr!S r"S r#S r$S r%S r&S r'S r(S r)\RT                   " S S\RV                  5      5       r,g) a  Command that statically validates gcloud commands for corectness.

To validate a command, run:

```
gcloud meta lint-gcloud-commands --command-string="gcloud compute instances
list"
```

To validate a list of commands in a file:

1) Create a JSON file with the following format:

```
[
  {
    "command_string": "gcloud compute instances list",
  },
  {
    "command_string": "gcloud compute instances describe my-instance",
  }
]
```

2) Then run the command:

```
gcloud meta lint-gcloud-commands --commands-file=commands.json
```

Commands can also be associated with an ID, which will be used to identify the
command in the output. Simply run:

```
gcloud meta lint-gcloud-commands --commands-file=commands.json --serialize
```
This will associated each command with using the index it was found in the file
as the ID. If you want to associate a command with a specific ID, you can do so
by adding the `id` field to the command in the JSON file. For example:

```
[
  {
    "command_string": "gcloud compute instances list",
    "id": 0,
  },
  {
    "command_string": "gcloud compute instances describe my-instance",
    "id": 1,
  }
]
```

This will output the validation results in the following format:

```
{"0": [{<OUTPUT_1>}], "1": [{<OUTPUT_2>}]}
    )absolute_import)division)unicode_literalsN)collections)gcloud_main)base)
exceptions)generate_argument_spec)log)yaml)filesF)command_stringsuccesscommand_argscommand_string_no_argsargs_structureerror_message
error_typez--helpc                       \ rS rSrSrg)CommandValidationErrorm    N)__name__
__module____qualname____firstlineno____static_attributes__r       (lib/surface/meta/lint_gcloud_commands.pyr   r   m   s    r   r   c                 T   [         R                  " U 5       n[        R                  " U5      nSSS5        Sn0 n[	        S W 5       5      nU HE  nUR                  S5      nU(       a  Uc  [        SUS    S35      eU=(       d    UXFS   '   US-  nMG     U$ ! , (       d  f       Nq= f)	z Reads commands from a JSON file.Nr   c              3   B   #    U  H  oR                  S 5      v   M     g7f)idN)get).0command_datas     r   	<genexpr>+_read_commands_from_file.<locals>.<genexpr>w   s     N<ML!!$''<Ms   r"   z,Not all commands have an ID. Id for command r   z	 is None.   )r   
FileReaderjsonloadanyr#   
ValueError)commands_filefcommand_file_dataref_idcommand_stringsneeds_idr%   
command_ids           r   _read_commands_from_filer5   q   s    &!		! '&/N<MNN('l!!$'JJ&+,-Y8  7A6JFO!123
aKF ( 
 '&s   B
B'r   c                    U R                  S5      S   n  [        R                  S:X  a  [        R                   " U SS9nO[        R                   " U 5      n U Vs/ s H  o"R                  S5      (       d  M  UPM     nnU Vs/ s H  o"R                  S5      (       a  M  UPM     nnXC-   $ ! [         a    [        S5      ef = fs  snf s  snf )z Move all flag arguments to back.#r   ntF)posix;Command could not be validated due to unforeseen edge case.--)splitosnameshlex	Exceptionr   
startswith)r   command_argumentsarg	flag_argsr   s        r   _separate_command_argumentsrE      s    !'',Q/.		ww$++nEB++n5 0H/s>>$3Gs/)H!2O!2#..:N#!2,O		!! 
 
 E 
 IOs)   )B-  B- C8CC!C-Cc                 l    SnSn[         R                  " XU 5      n[         R                  " SSU5      nU$ )zLAdds equals signs to gcloud command flags, except for format and help flags.z(--[a-zA-Z0-9-]+) +([^-][^ ]*)z\1=\2z(--[a-zA-Z0-9-]+)= z\1 )resub)commandpatternreplacementmodified_commands       r   _add_equals_to_flagsrM      s?     ( 
 +VVG':VV2F<LM	r   c                     [        U 5      n U R                  SS5      R                  SS5      R                  SS5      R                  SS5      n U $ )Nz--project=PROJECT z--project=my-project z--project=PROJECT_ID z$PROJECT_ID zmy-project zYOUR_PROJECT_ID )rM   replace)command_strs    r   formalize_gcloud_commandrQ      sR    $[1+.0GHw&(?@w~}-w!=1	  
r   c                 N   [        U S5      R                  S5      n SnSn[        R                  " U SU 3[        R                  5      n/ nUR                  U 5       H  nUR                  S5      R                  5       nSU;  d  UR                  S5      (       d  M@  UR                  S5       Ho  nUR                  S	5      n[        U5      S:  d  M%  US
   R                  5       (       d  M?  [        US
   R                  5       5      nUR                  SU 35        Mq     M     U$ )zExtracts code snippets from fenced code blocks within a text string.

Args:
    text: The text string containing fenced code blocks.

Returns:
    A list of extracted code snippets.
zutf-8unicode_escapez```(?:[\w ]+\n)?(.*?)```z(?: {3-8}|\t)(.*?)(?:\n\S|\n$)|r(   zgcloud gcloud
r   )bytesdecoderG   compileDOTALLfinditergroupstriprA   r<   lenrQ   append)	textfenced_patternindented_patterncombined_patterncode_snippetsmatchrP   cmdcmd_new_liness	            r   _extract_gcloud_commandsrh      s    
tW		$	$%5	6$..'  ZZ	*+,bii -((
e ++a.&&(K#;+A+A(+K+K  +iiom	]	q	 ]1%5%;%;%=%=.}Q/?/E/E/GHw{m45	 , 
r   c                     [         R                  " / 5      nU SS n UR                  5       nU  H9  nUR                  S5      (       a    U$ UR	                  U5      nU(       d    U$ UnM;     U$ )z9Returns the command node for the given command arguments.r(   Nr;   )r   	CreateCLI_TopElementrA   LoadSubElement)rB   clicurrent_command_nodeargumentchild_command_nodes        r   _get_command_noderq      s    b!#'+*#h4  
 
	 .<<XF	 . $ 
r   c                 L    SR                  U R                  R                  5      $ )1Returns the command string without any arguments. )joinaicommand_name)command_nodes    r   _get_command_no_argsry      s    	,//..	//r   c                 2    [         R                  " U 5      nU$ )rs   )r
   GenerateArgumentSpecifications)rx   argument_trees     r   _get_command_args_treer}      s    (GG- 
r   c                 Z   ^^^^ / mU4S jmU4S jmUU4S jmU  H  nT" U5        M     T$ )z&Returns a dict of positional metavars.c                    > SU ;   a8  U R                  SS5      (       a   U S   (       a  TR                  U S   5        g g g g )Nr>   
positionalF)r#   r_   )nodepositional_argss    r   _process_arg._get_positional_metavars.<locals>._process_arg   s?    ~$((<77	ftF|, 
 8~r   c                 (   > U  H  nT" U5        M     g )Nr   )r   rC   _traverse_trees     r   _traverse_arg_group5_get_positional_metavars.<locals>._traverse_arg_group   s    S r   c                 D   > SU ;   a  U S   S   nT" U5        g T" U 5        g )Nr\   	argumentsr   )r   r\   r   r   s     r   r   0_get_positional_metavars.<locals>._traverse_tree   s(    $7mK(e% 4r   r   )	args_treer   r   r   r   r   s     @@@@r   _get_positional_metavarsr      s3     /-
 d4 	r   c                   ^	^
^ [        5       m0 n[        US   5      m
S nU" U 5      n U	U
U4S jnSnU  Hn  m	T	nT	R                  S5      (       a(  T	R                  S5      nUS:w  a  T	SU nT	US	-   S nO"S
nOU" 5       u  phU=(       d    T	nU=(       d    S
nUUS.X&'   US	-  nMp     [        R
                  " [        UR                  5       S S95      $ )z$Normalizes command args for storage.r   c                     [        U  Vs/ s H  oR                  S5      (       d  M  UPM     sn5      nU  Vs/ s H  oR                  S5      (       a  M  UPM     nnX2-   $ s  snf s  snf )zSorts command arguments.

Arguments starting with '--' are placed at the back, and all arguments are
ordered alphabetically.

Args:
  args: The command arguments to sort.

Returns:
  The sorted command arguments.
r;   )sortedrA   )argsrC   rD   r   s       r   _sort_command_args3_normalize_command_args.<locals>._sort_command_args  sU     tDt~~d/CtDEI&*Gds..2FsdOG&& EGs   A!A!A&A&c                  t   > T H1  n U T;  d  M  TnU R                  5       nTR                  U 5        X!4s  $    g)N)NN)upperadd)positional_metavarcommand_valuecommand_arg_namecommand_argpositional_args_in_treepositionals_useds      r   "_get_next_available_positional_argC_normalize_command_args.<locals>._get_next_available_positional_arg  sH    5	#3	3#-335/0.. 6 r   r   r;   =Nr(    )valueindexc                     U S   S   $ )Nr(   r   r   )items    r   <lambda>)_normalize_command_args.<locals>.<lambda>?  s    d1gg6Fr   )key)setr   rA   findr   OrderedDictr   items)r   r   arg_name_valuer   r   	arg_indexr   equals_indexr   r   r   r   s            @@@r   _normalize_command_argsr     s    U.4Y{5KL'  $L1, )!k"d## %%c*l		&}5#L1$4$67 )K(L% *8[#)rm(N$ NI) "* 
	 	 ^!!#)FG
 r   c                       \ rS rSrSr\R                  " 5       r\R                  " 5       r/ r	Sr
SrSS jrS rS rS rS r   SS
 jrS r\S 5       rS rSrg	)GenerateCommandiC  zrGenerate YAML file to implement given command.

The command YAML file is generated in the --output-dir directory.
Fc                     [        U5      n[        U5      nU R                  X1U5      u  pEnU(       d  gU R                  XVX5      nU(       d  gU R	                  SXU5        g)zValidate a single command.NT)rQ   rE   _validate_command_prefix_validate_command_suffix_store_validation_results)selfr   r1   rB   command_successrx   flag_argumentsflag_successs           r   _validate_command!GenerateCommand._validate_commandP  sh    -n=N3NC%%&7P 2O> 00nL ""4Pr   c           
          [        U5      nUR                  5        H  u  p4 U R                  X45        M     g! [         a$  nU R	                  SUUSSU 3S5         SnAME  SnAff = f)z+Validate multiple commands given in a file.FNz Command could not be validated: r   )r5   r   r   r@   r   )r   r.   commandsrI   r1   es         r   _validate_commands_from_file,GenerateCommand._validate_commands_from_file`  sp    '6H#>>+

w/ ,  
&&.qc2$	
 	

s   8
A&A!!A&c                     [         R                  " U5       nUR                  5       nSSS5        [        W5      nSnU H  nU R	                  Xe5        US-  nM     g! , (       d  f       N;= f)z2Validate multiple commands given in a text string.Nr   r(   )r   r)   readrh   r   )r   commands_text_filer/   r`   r   r1   rI   s          r   _validate_commands_from_text,GenerateCommand._validate_commands_from_textp  s\    			,	-VVXd 
.'-HF
W-kf 	 
.	-s   A
A+c           
         [         R                  " / 5      nUSS nSnUR                  5       nU H  nUR                  S5      (       a	  SUXS 4s  $ UR	                  U5      nU(       d)  U R                  SUUXS SR                  U5      S5          g	US-  nUR                  (       a  M{  SUXS 4s  $    XS nU(       d  U R                  SUUXS S
S5        g	[        S5      e)zDValidate that the argument string contains a valid command or group.r(   Nr   r;   TFzInvalid choice: '{}'UnrecognizedCommandError)FNNzCommand name argument expectedr:   )	r   rj   rk   rA   rl   r   formatis_groupr   )	r   rB   r   r1   rm   r   rn   ro   remaining_flagss	            r   r   (GenerateCommand._validate_command_prefixz  s*   



#C)!"-E??,% 
		T	"	" f%
 	
 2@@J!&&f%"))(3&	
 !qje!*** f%
 	
3 &@ (/O
$$



F
#
*
$  !E r   c                 @   [          H
  nXR;   d  M
    g   SnU(       a  U H  nSU;   d  SU;   d  SU;   d  M  SnM     U(       d  / nU(       d  UR                  S5         UR                  R                  USS9  g! [        R
                  [        R                  [        R                  4 a     g[        R                   a[  nS[        U5      ;   a   S	nAgU R                  SUUU[        R                  " U5      [!        U5      R"                  5         S	nAgS	nAff = f)
zDValidates that the given flags can be parsed by the argparse parser.TFz	--projectz--folderz--organizationz--project=myproject)raise_errorzNo such file or directoryN)_IGNORE_ARGSr_   _parser
parse_argsr   MissingFileErrorgcloud_exceptionsBadFileExceptionr   FileLoadErrorargparseArgumentErrorstrr   six	text_typetyper   )	r   rx   rB   r   r1   ignored_argfound_parentr   r   s	            r   r   (GenerateCommand._validate_command_suffix  s    $		) $ L*+;&[(;., + 45%%&7T%J& # 	** 
   !! 	$A	.
$$




--

q'

 s$   A: :3D/DD=DDNc                    [         R                  " [        5      nX'S'    [        [	        U5      5      n[        U5      US'   [        U5      US'   U(       a  [        XGS   5      US'   XS'   XWS'   XgS'   [        R                  " [        UR                  5       5      5      n	U R                  (       a>  X0R                  ;  a  U	/U R                  U'   OU R                  U   R                  U	5        U R                   (       a  U	U R"                  U'   gU R$                  R                  U	5        g! [         a    X'S'    Nf = f)	z4Store information related to the command validation.r   r   r   r   r   r   r   N)copydeepcopy_PARSING_OUTPUT_TEMPLATErq   rE   ry   r}   r@   r   r   r   r   r   serialize_results_SERIALIZED_VALIDATION_RESULTSr_   index_results_INDEXED_VALIDATION_RESULTS_VALIDATION_RESULTS)
r   r   r   r1   r   r   r   validation_outputrx   sorted_validation_outputs
             r   r   )GenerateCommand._store_validation_results  sR    &>?*8&'	C&
%n
5l 5I
501 -C<,P() *A
*:;+' $+i )6o&&0l#*66 &&()  	::	:7O6P++F3++F3::$	
 
" &&~6 %%&>?1  C4B01Cs   0D- -D>=D>c                    U R                   (       a>  [        R                  R                  [        R
                  " U R                  5      5        gU R                  (       a>  [        R                  R                  [        R
                  " U R                  5      5        g[        R                  R                  [        R
                  " U R                  5      5        g)z$Output collected validation results.N)
r   r   outPrintr*   dumpsr   r   r   r   )r   s    r   _log_validation_results'GenerateCommand._log_validation_results
  sq    	ggmmDJJt??@A				ggmmDJJtBBCD	ggmmDJJt7789r   c                     U R                  SS9nUR                  SSS9  UR                  SSS9  UR                  SS	S9  U R                  S
SSS9  g )NT)mutexz--command-stringz&Gcloud command to statically validate.)helpz--commands-filez9JSON file containing list of gcloud commands to validate.z--commands-text-filezRaw text containing gcloud command(s) to validate. For example, the commands could be in fenced code blocks or indented code blocks.z--serialize
store_truez:Output results in a dictionary serialized by reference id.)actionr   )	add_groupadd_argument)parsercommand_groups     r   ArgsGenerateCommand.Args  s    $$4$0M5   H      I  r   c                 R   UR                   (       a  SU l        UR                  S5      (       a  U R                  UR                  5        OMUR                  S5      (       a  U R                  UR                  5        OU R                  UR                  5        U R                  5         g )NTr   r   )
	serializer   IsSpecifiedr   r   r   r   r   r.   r   )r   r   s     r   RunGenerateCommand.Run,  s}    ~~#d())
T001			.	/	/
''(?(?@
''(:(:;  "r   )r   )r   )NNN)r   r   r   r   __doc__r   r   r   r   r   r   r   r   r   r   r   r   r   r   staticmethodr   r   r   r   r   r   r   r   C  s    
 !, 7 7 9#.#:#:#< -Q 
 6p(^ ,@\:  0	#r   r   )-r  
__future__r   r   r   r   r   r*   r=   rG   r?   typingr   googlecloudsdkr   googlecloudsdk.callioper   r	   r   googlecloudsdk.command_lib.metar
   googlecloudsdk.corer   r   googlecloudsdk.core.utilr   r   r   r   r@   r   r5   r   rE   rM   rQ   rh   rq   ry   r}   r   r   UniverseCompatibleCommandr   r   r   r   <module>r     s   9v '  '    	 	   & ( C B # $ * 
 "  zY &" "&
B0
4:z q#dll q# q#r   