
    +0                     r   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
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r " S S\R.                  5      r " S S\5      rS rS rS r\R8                  S 5       r " S S\5      rS r  " S S\5      r! " S S\5      r"g)z/Utilities for gcloud help document differences.    )absolute_import)division)unicode_literalsN)
exceptions)log)
console_io)progress_tracker)files)parallel)text    c                       \ rS rSrSrSrg)Error*   zErrors for this module. N__name__
__module____qualname____firstlineno____doc____static_attributes__r       0lib/googlecloudsdk/command_lib/meta/help_util.pyr   r   *   s    r   r   c                       \ rS rSrSrSrg)HelpUpdateError.   zUpdate errors.r   Nr   r   r   r   r   r   .   s    r   r   c                 F    [         R                  R                  U 5      S:H  $ )z-Return True if path refers to an OWNERS file.OWNERS)ospathbasename)r!   s    r   IsOwnersFiler#   2   s    			$	8	++r   c                      [         R                  " U 5      nSnX4$ ! [         a    [         R                  " U 5      nSn X4$ f = f)zReturns the file contents and whether or not the file contains binary data.

Args:
  file: A file path.

Returns:
  A tuple of the file contents and whether or not the file contains binary
  contents.
FT)
file_utilsReadFileContentsUnicodeErrorReadBinaryFileContents)filecontents	is_binarys      r   GetFileContentsr,   7   sV    **40HI 
	 
 006HI		s    "AAc                 2   [        5       n[        R                  " [        R                  " U 5      5       H^  u  p#nU HR  n[        R
                  R                  X%5      n[        R
                  R                  X`5      nUR                  U5        MT     M`     U$ )zGenerates the set of all files in directory and its children recursively.

Args:
  directory: The directory path name.

Returns:
  A set of all files in directory and its children recursively, relative to
  the directory.
)	setr    walksix	text_typer!   joinrelpathadd)	directorydirfilesdirpath_r
   namer)   relative_files           r   GetDirFilesRecursiver;   J   sm     U(773==#;<g%WW\\'(dggood6mll=!  = 
/r   c              #   (  #    [         R                  " U SS9   [        R                  " 5       nSv   [        R                  " 5       U-
  n[        R                  R                  SR                  X5      5        SSS5        g! , (       d  f       g= f7f)z:Context manager to track progress and time blocks of code.T)autotickNz{} took {} seconds)r	   ProgressTrackertimer   statusPrintformat)messagestartelapsed_times      r   TimeItrF   ^   s_      ''$?IIKE	99;&LJJ)00GH	 @??s   BA B8	B
BBc                   :    \ rS rSrSrS rS rS
S jrS rS r	S	r
g)DiffAccumulatorh   z0A module for accumulating DirDiff() differences.c                     SU l         g )Nr   _changesselfs    r   __init__DiffAccumulator.__init__k   s	    DMr   c                     g)Checks if relative_file should be ignored by DirDiff().

Args:
  relative_file: A relative file path name to be checked.

Returns:
  True if path is to be ignored in the directory differences.
Fr   )rN   r:   s     r   IgnoreDiffAccumulator.Ignoreo   s     r   Nc                 .    U =R                   S-  sl         g)a  Called for each file difference.

AddChange() can construct the {'add', 'delete', 'edit'} file operations that
convert old_dir to match new_dir. Directory differences are ignored.

This base implementation counts the number of changes.

Args:
  op: The change operation string;
    'add'; relative_file is not in old_dir.
    'delete'; relative_file is not in new_dir.
    'edit'; relative_file is different in new_dir.
  relative_file: The old_dir and new_dir relative path name of a file that
    changed.
  old_contents: The old file contents.
  new_contents: The new file contents.

Returns:
  A prune value. If non-zero then DirDiff() returns immediately with that
  value.
   NrK   rN   opr:   old_contentsnew_contentss        r   	AddChangeDiffAccumulator.AddChange{   s    , 	MMQMr   c                     U R                   $ )z Returns the accumulated changes.rK   rM   s    r   
GetChangesDiffAccumulator.GetChanges   s    ==r   c                     g)zCalled for each file for content validation.

Args:
  relative_file: The old_dir and new_dir relative path name of an existing
    file.
  contents: The file contents string.
Nr   )rN   r:   r*   s      r   ValidateDiffAccumulator.Validate   s     	r   rK   NN)r   r   r   r   r   rO   rS   r[   r^   ra   r   r   r   r   rH   rH   h   s    8	2	r   rH   c                   ^ ^^^ [        S5         [        T5      nSSS5        [        S5         [        T 5      mSSS5        UUU U4S jn[        R                  " S5       n/ nW H>  nTR	                  U5      (       a  M  UR                  XG45      nUR                  U5        M@     U HG  n	U	R                  5       nU(       d  M  Uu  ppTR                  XX5      nU(       d  M<  Us  sSSS5        $    SSS5        T H@  nTR	                  U5      (       a  M  UW;  d  M#  TR                  SU5      nU(       d  M>  Us  $    g! , (       d  f       GN0= f! , (       d  f       GN#= f! , (       d  f       Ny= f)a  Calls diff.AddChange(op, file) on files that changed from old_dir new_dir.

diff.AddChange() can construct the {'add', 'delete', 'edit'} file operations
that convert old_dir to match new_dir. Directory differences are ignored.

Args:
  old_dir: The old directory path name.
  new_dir: The new directory path name.
  diff: A DiffAccumulator instance.

Returns:
  The return value of the first diff.AddChange() call that returns non-zero
  or None if all diff.AddChange() calls returned zero.
zGetDirFilesRecursive new filesNzGetDirFilesRecursive old filesc                   > [        [        R                  R                  TU 5      5      u  pU(       d  TR	                  X5        U T;   a;  [        [        R                  R                  TU 5      5      u  p4XB:X  a  X1:X  a  gSXU4$ SU SU4$ )z$Diffs a file in new_dir and old_dir.Neditr4   )r,   r    r!   r2   ra   )	r)   rZ   
new_binaryrY   
old_binarydiffnew_dirold_dir	old_filess	        r   	_FileDiffDirDiff.<locals>._FileDiff   s|    .rww||GT/JKL
mmD'y!0gt1L!Ml		!l&BT55D$,,r      delete)	rF   r;   r   GetPoolrS   
ApplyAsyncappendGetr[   )rk   rj   ri   	new_filesrm   poolresultsr)   resultresult_futurerX   rY   rZ   prunerl   s   ```           @r   DirDiffr{      s=    ./$W-I 0./$W-I 0- - tG	T		y'2fnnV	  !  "f	/5,,rD5,  !   d{{49nnXt,e	  
U 0///" s5   EE"A!E)E)'E)4E)
E
E&)
E7c                   @   ^  \ rS rSrSrSU 4S jjrS rSS jrSrU =r	$ )	HelpAccumulator   zAccumulates help document directory differences.

Attributes:
  _changes: The list of DirDiff() (op, path) difference tuples.
  _restrict: The set of file path prefixes that the accumulator should be
    restricted to.
c                    > [         [        U ]  5         / U l        U(       aH  U Vs1 s H4  n[        R
                  R                  UR                  S5      SS  5      iM6     snU l        g 0 U l        g s  snf )N.rV   )	superr}   rO   rL   r    sepr2   split	_restrict)rN   restrictr	__class__s      r   rO   HelpAccumulator.__init__   s\    	/4)+DM! ?GGhrvv{{1773<#34hGDN') 	NGs   ;A2c                     [        U5      (       a  gU R                  (       d  gU R                   H1  nX:X  d)  UR                  U[        R                  -   5      (       d  M1    g   g)rR   TF)r#   r   
startswithr    r   )rN   r:   items      r   rS   HelpAccumulator.Ignore   sP     M"">>		-":":4"&&="I"I  r   c                 <    U R                   R                  X45        g)aG  Adds an DirDiff() difference tuple to the list of changes.

Args:
  op: The difference operation, one of {'add', 'delete', 'edit'}.
  relative_file: The relative path of a file that has changed.
  old_contents: The old file contents.
  new_contents: The new file contents.

Returns:
  None which signals DirDiff() to continue.
N)rL   rs   rW   s        r   r[   HelpAccumulator.AddChange   s     	MM",-r   )rL   r   Nrc   )
r   r   r   r   r   rO   rS   r[   r   __classcell__)r   s   @r   r}   r}      s    +$ r   r}   c                   <    \ rS rSrSrS	S jrS rS
S jrS
S jrSr	g)HelpUpdateri  a$  Updates the document directory to match the current CLI.

Attributes:
  _cli: The Current CLI.
  _directory: The help document directory.
  _generator: The document generator.
  _hidden: Boolean indicating whether to update hidden commands.
  _test: Show but do not apply operations if True.
c                     [         R                  R                  U5      (       d  [        SU-  5      eXl        X l        X0l        XPl        X@l        g)aY  Constructor.

Args:
  cli: The Current CLI.
  directory: The help document directory.
  generator: An uninstantiated walker_util document generator.
  test: Show but do not apply operations if True.
  hidden: Boolean indicating whether the hidden commands should be used.

Raises:
  HelpUpdateError: If the destination directory does not exist.
z,Destination directory [%s] must be absolute.N)	r    r!   isabsr   _cli
_directory
_generator_hidden_test)rN   clir5   	generatortesthiddens         r   rO   HelpUpdater.__init__  sG     77==##
89
DF FIOOLJr   c           
         [         R                  " 5        n[        R                  " SS9n[	        S5         U R                  U R                  X#R                  US9nSSS5        [        R                  " 5       nUR                  5         WR                  SS9  UR                  5         [        R                  " 5       U-
  n[        R                  " SR                  U5      5        [        US9n[	        S	5         [!        U R"                  X'5        SSS5        [$        R&                  " [(        5      nS
n	[	        S5         [+        UR-                  5       5       Hf  u  pU	S-  n	U R.                  (       a
  U	[0        :  a.  [        R2                  R5                  SR                  X5      5        X   R7                  U5        Mh     SSS5        U R.                  (       a  U	(       am  U	[0        :  a  [        R2                  R5                  S5        [        R2                  R5                  SR                  U	[8        R:                  " U	S5      5      5        U	sSSS5        $ [	        S5         S H  n
X    H  n[<        R>                  RA                  U R"                  U5      nU
S;   ay  U
S:X  a<  [<        R>                  RC                  U5      nU(       a  [         RD                  " U5        [<        R>                  RA                  X+5      n[F        RH                  " X5        M  U
S:X  d  M   [<        RJ                  " U5        M     M     SSS5        U	sSSS5        $ ! , (       d  f       GN= f! , (       d  f       GN_= f! , (       d  f       GN= f! [L         a     GM*  f = f! , (       d  f       Na= f! , (       d  f       g= f)zEUpdate() helper method. Returns the number of changed help doc files.zGenerating Help Document Files)labelzCreating walkerr   NTr   z.Generating Help Document Files took {} secondsDiffingr   zGetting diffsrV   z{0} {1}z...z{0} help text {1} changedr)   zUpdating destination files)r4   rf   rp   )r4   rf   r4   rp   )'r%   TemporaryDirectoryr   ProgressBarrF   r   r   SetProgressr?   StartWalkFinishr   inforB   r}   r{   r   collectionsdefaultdictlistsortedr^   r   TEST_CHANGES_DISPLAY_MAXr@   rA   rs   r   	Pluralizer    r!   r2   dirnameMakeDirshutilcopyfileremoveOSError)rN   r   temp_dirpbwalkerrD   rE   ri   opschangesrX   r!   	dest_pathsubdir	temp_paths                  r   _UpdateHelpUpdater._Update1  s   		&	&	(H!!(HIb#$IIx( ! D % iikehhjkkkiikYY[5(l	hh
:
A
A,
O h/d)0 ##D)cg/"t01HB
Q,'w)AAJJY--b78
'..
	 2 # 
00JJU#
**

6==t~~gv68 9G 
)	(J ./+BgdT__d;I_$u3$$V,'',,x6iooi3x		)$  , 0" m 
)	( %$ 
 #":   0/K 
)	(s    N/&MBN/9M(/N/?BM:BN/N/&B:N%N;N	N/
M%	 N/(
M7	2N/:
N		N/
NNNN
N,	(N//
N=Nc                 0   [         R                  R                  U R                  5      (       d  [	        SU R                  -  5      e U R                  U5      $ ! [        [        [        4 a'  n[	        S[        R                  " U5      -  5      eSnAff = f)a  Updates the help document directory to match the current CLI.

Args:
  restrict: Restricts the walk to the command/group dotted paths in this
    list. For example, restrict=['gcloud.alpha.test', 'gcloud.topic']
    restricts the walk to the 'gcloud topic' and 'gcloud alpha test'
    commands/groups.

Raises:
  HelpUpdateError: If the destination directory does not exist.

Returns:
  The number of changed help document files.
z8Destination directory [%s] must exist and be searchable.zUpdate failed: %sN)r    r!   isdirr   r   r   IOErrorr   SystemErrorr0   r1   )rN   r   es      r   UpdateHelpUpdater.Updatek  s     77==))
D
// D\\(##Wk* D/#--2BBCCDs   A B."BBc                 (   [         R                  " 5        nU R                  U R                  USUS9nUR	                  SS9  [        US9n[        U R                  X$5        [        UR                  5       5      sSSS5        $ ! , (       d  f       g= f)zFPrint a list of help text files that are distinct from source, if any.Nr   Tr   )
r%   r   r   r   r   r}   r{   r   r   r^   )rN   r   r   r   ri   s        r   GetDiffFilesHelpUpdater.GetDiffFiles  sq    		&	&	(H
))Xth  8fkkkh/ddoox.DOO%& 
)	(	(s   A#B
B)r   r   r   r   r   )FFr   )
r   r   r   r   r   rO   r   r   r   r   r   r   r   r   r     s    ,8tD0'r   r   )#r   
__future__r   r   r   r   
contextlibr    r   r?   googlecloudsdk.corer   r   googlecloudsdk.core.consoler   r	   googlecloudsdk.core.utilr
   r%   r   r   r0   r   r   r   r#   r,   r;   contextmanagerrF   objectrH   r{   r}   r   r   r   r   <module>r      s     6 &  '   	   * # 2 8 8 - ) 
   J  e ,
&( I I8	f 8	v9x.o .b{'& {'r   