
    +0                     r   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	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dZ G d dej.                        Z G d de      Zd Zd Zd Zej8                  d        Z G d de      Zd Z  G d de      Z! G d de      Z"y)z/Utilities for gcloud help document differences.    )absolute_import)division)unicode_literalsN)
exceptions)log)
console_io)progress_tracker)files)parallel)text    c                       e Zd ZdZy)ErrorzErrors for this module.N__name__
__module____qualname____doc__     0lib/googlecloudsdk/command_lib/meta/help_util.pyr   r   *   s    r   r   c                       e Zd ZdZy)HelpUpdateErrorzUpdate errors.Nr   r   r   r   r   r   .   s    r   r   c                 F    t         j                  j                  |       dk(  S )z-Return True if path refers to an OWNERS file.OWNERS)ospathbasename)r   s    r   IsOwnersFiler   2   s    			$	8	++r   c                     	 t        j                  |       }d}||fS # t        $ r t        j                  |       }d}Y ||fS w xY w)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   sZ    **40HI 
9	 
 006HI	9	s     AAc                 ,   t               }t        j                  t        j                  |             D ]^  \  }}}|D ]S  }t        j
                  j                  ||      }t        j
                  j                  ||       }|j                  |       U ` |S )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   GetDirFilesRecursiver7   J   ss     U(773==#;<gq%WW\\'4(dggoodI6mll=!  = 
/r   c              #      K   t        j                  | d      5  t        j                         }d t        j                         |z
  }t        j                  j                  dj                  | |             ddd       y# 1 sw Y   yxY ww)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   TimeItrB   ^   sb      ''$?IIKE	99;&LJJ)00,GH	 @??s   BAB9	BBBc                   0    e Zd ZdZd Zd ZddZd Zd Zy)	DiffAccumulatorz0A module for accumulating DirDiff() differences.c                     d| _         y )Nr   _changesselfs    r   __init__zDiffAccumulator.__init__k   s	    DMr   c                      y)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   )rI   r6   s     r   IgnorezDiffAccumulator.Ignoreo   s     r   Nc                 .    | xj                   dz  c_         y)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.
       NrF   rI   opr6   old_contentsnew_contentss        r   	AddChangezDiffAccumulator.AddChange{   s    , 	MMQMr   c                     | j                   S )z Returns the accumulated changes.rF   rH   s    r   
GetChangeszDiffAccumulator.GetChanges   s    ==r   c                      y)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   )rI   r6   r&   s      r   ValidatezDiffAccumulator.Validate   s     	r   NN)	r   r   r   r   rJ   rM   rT   rV   rX   r   r   r   rD   rD   h   s    8	2	r   rD   c                     t        d      5  t              }ddd       t        d      5  t               ddd        fd}t        j                  d      5 }g }D ]8  }j	                  |      r|j                  ||f      }|j                  |       : |D ]?  }	|	j                         }|s|\  }
}}}j                  |
|||      }|s4|c cddd       S  	 ddd       D ]1  }j	                  |      r|vsj                  d|      }|s/|c S  y# 1 sw Y   
xY w# 1 sw Y   xY w# 1 sw Y   YxY w)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                    t        t        j                  j                  |             \  }}|sj	                  | |       | v r=t        t        j                  j                  |             \  }}||k(  r||k(  ryd| ||fS d| d|fS )z$Diffs a file in new_dir and old_dir.Neditr0   )r(   r   r   r.   rX   )	r%   rS   
new_binaryrR   
old_binarydiffnew_dirold_dir	old_filess	        r   	_FileDiffzDirDiff.<locals>._FileDiff   s    .rww||GT/JKL*
mmD,'y!0gt1L!MlJ	z	!ll&BT<55D$,,r      delete)	rB   r7   r   GetPoolrM   
ApplyAsyncappendGetrT   )ra   r`   r_   	new_filesrc   poolresultsr%   resultresult_futurerQ   rR   rS   prunerb   s   ```           @r   DirDiffrp      s6    ./$W-I 0./$W-I 0- tG	T	y4'2fnnV	  !  "f	/5,D,r4|D,  !   d{{49nnXt,e	  
U 0///" s5   D$D1 AD=8D=D=#D=$D.1D:=Ec                   2     e Zd ZdZd fd	Zd ZddZ xZS )HelpAccumulatorzAccumulates 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                     t         t        |           g | _        |rE|D ch c]3  }t        j
                  j                  |j                  d      dd        5 c}| _        y i | _        y c c}w )N.rO   )	superrr   rJ   rG   r   sepr.   split	_restrict)rI   restrictr	__class__s      r   rJ   zHelpAccumulator.__init__   s\    	/4)+DM! ?GGhrvv{{1773<#34hGDN') 	NGs   8A*c                     t        |      ry| j                  sy| j                  D ]+  }||k(  s#|j                  |t        j                  z         s+ y y)rL   TF)r   rx   
startswithr   rv   )rI   r6   items      r   rM   zHelpAccumulator.Ignore   sL     M">>	$	-":":4"&&="I  r   c                 >    | j                   j                  ||f       y)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)rG   rh   rP   s        r   rT   zHelpAccumulator.AddChange   s     	MM"m,-r   NrY   )r   r   r   r   rJ   rM   rT   __classcell__)r{   s   @r   rr   rr      s    +$r   rr   c                   .    e Zd ZdZddZd ZddZddZy)	HelpUpdatera2  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                     t         j                  j                  |      st        d|z        || _        || _        || _        || _        || _        y)a}  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)rI   clir1   	generatortesthiddens         r   rJ   zHelpUpdater.__init__  sN     77==#
89
DF FDIDODODLDJr   c           
         t        j                         5 }t        j                  d      }t	        d      5  | j                  | j                  ||j                  |      }ddd       t        j                         }|j                          j                  d       |j                          t        j                         |z
  }t        j                  dj                  |             t        |      }t	        d	      5  t!        | j"                  ||       ddd       t%        j&                  t(              }d
}	t	        d      5  t+        |j-                               D ]b  \  }
}|	dz  }	| j.                  r	|	t0        k  r/t        j2                  j5                  dj                  |
|             ||
   j7                  |       d 	 ddd       | j.                  rx|	rk|	t0        k\  rt        j2                  j5                  d       t        j2                  j5                  dj                  |	t9        j:                  |	d                   |	cddd       S t	        d      5  dD ]  }
||
   D ]  }t<        j>                  jA                  | j"                  |      }|
dv rr|
dk(  r6t<        j>                  jC                  |      }|rt        jD                  |       t<        j>                  jA                  ||      }tG        jH                  ||       |
dk(  s	 t=        jJ                  |         	 ddd       |	cddd       S # 1 sw Y   xY w# 1 sw Y   6xY w# 1 sw Y   xY w# tL        $ r Y 
w xY w# 1 sw Y   KxY w# 1 sw Y   yxY w)zEUpdate() helper method. Returns the number of changed help doc files.zGenerating Help Document Files)labelzCreating walkerry   NTr   z.Generating Help Document Files took {} secondsDiffingr   zGetting diffsrO   z{0} {1}z...z{0} help text {1} changedr%   zUpdating destination files)r0   r\   re   )r0   r\   r0   re   )'r!   TemporaryDirectoryr   ProgressBarrB   r   r   SetProgressr;   StartWalkFinishr   infor>   rr   rp   r   collectionsdefaultdictlistsortedrV   r   TEST_CHANGES_DISPLAY_MAXr<   r=   rh   r   	Pluralizer   r   r.   dirnameMakeDirshutilcopyfileremoveOSError)rI   ry   temp_dirpbwalkerr@   rA   r_   opschangesrQ   r   	dest_pathsubdir	temp_paths                  r   _UpdatezHelpUpdater._Update1  s   		&	&	(H!!(HIb#$IIx( ! D % iikehhjkkkiikYY[5(l	hh
:
A
A,
O h/d)40 ##D)cg/"t01HB
Q,'w)AAJJY--b$78
b'..
	 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M.NA?MBNNB3M7M'(M7-	N M
	NM	NM$	N'	M40M73M44M77N 	<NNNc                 "   t         j                  j                  | j                        st	        d| j                  z        	 | j                  |      S # t        t        t        f$ r&}t	        dt        j                  |      z        d}~ww xY w)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   SystemErrorr,   r-   )rI   ry   es      r   UpdatezHelpUpdater.Updatek  s|     77==)
D
// D\\(##Wk* D/#--2BBCCDs   A B(!B		Bc                 0   t        j                         5 }| j                  | j                  |d|      }|j	                  d       t        |      }t        | j                  ||       t        |j                               cddd       S # 1 sw Y   yxY w)zFPrint a list of help text files that are distinct from source, if any.Nr   Tr   )
r!   r   r   r   r   rr   rp   r   r   rV   )rI   ry   r   r   r_   s        r   GetDiffFileszHelpUpdater.GetDiffFiles  ss    		&	&	(H
))Xth  8fkkkh/ddoox.DOO%& 
)	(	(s   A-BB)FFr   )r   r   r   r   rJ   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   r,   r   r   r   r   r(   r7   contextmanagerrB   objectrD   rp   rr   r   r   r   r   <module>r      s     6 &  '   	   * # 2 8 8 - ) 
   J  e ,
&( I I8	f 8	v9x.o .b{'& {'r   