
    +6                        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rSSKJr   " S S\R*                  5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      rS rS r\R
                  R:                  4S jrS rS r S r!S r"  S'S jr#S(S  jr$S! r%S" r& " S# S$\'5      r( " S% S&\'5      r)g))z!Utility functions for gcloud app.    )absolute_import)division)unicode_literalsN)client_deployinfo)config)
exceptions)log)	platforms)urllibc                       \ rS rSrSrSrg)Error%   z!Exceptions for the appcfg module. N__name__
__module____qualname____firstlineno____doc____static_attributes__r       &lib/googlecloudsdk/api_lib/app/util.pyr   r   %   s    )r   r   c                       \ rS rSrSrSrg)NoFieldsSpecifiedError)   zFThe user specified no fields to a command which requires at least one.r   Nr   r   r   r   r   r   )   s    Nr   r   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )NoCloudSDKError-   z(The module was unable to find Cloud SDK.c                 ,   > [         [        U ]  S5        g )Nz(Unable to find a Cloud SDK installation.)superr   __init__self	__class__s    r   r!   NoCloudSDKError.__init__0   s    	/4)24r   r   r   r   r   r   r   r!   r   __classcell__r$   s   @r   r   r   -   s    04 4r   r   c                       \ rS rSrSrSrg)NoAppengineSDKError5   z0The module was unable to find the appengine SDK.r   Nr   r   r   r   r*   r*   5   s    8r   r*   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )TimeoutError9   z<An exception for when a retry with wait operation times out.c                 ,   > [         [        U ]  S5        g )Nz0Timed out waiting for the operation to complete.)r    r-   r!   r"   s    r   r!   TimeoutError.__init__<   s    	,&:<r   r   r&   r(   s   @r   r-   r-   9   s    D< <r   r-   c                   0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )RPCErrorA   z1For when an error occurs when making an RPC call.c           
         > [         [        U ]  SR                  UR                  [        USS5      US95        Xl        g )Nz9Server responded with code [{code}]:
  {reason}.
  {body}reasonz	(unknown))coder5   body)r    r2   r!   formatr6   getattr	url_error)r#   r:   r7   r$   s      r   r!   RPCError.__init__D   s@    	(D"E	Y^^y(K@ 
 

 Nr   )r:    r&   r(   s   @r   r2   r2   A   s    9 r   r2   c                      [         R                  " 5       R                  n U (       d
  [        5       e[        R
                  " SU 5        U $ )zGets the directory of the root of the Cloud SDK, error if it doesn't exist.

Raises:
  NoCloudSDKError: If there is no SDK root.

Returns:
  str, The path to the root of the Cloud SDK.
zFound Cloud SDK root: %s)r   Pathssdk_rootr   r	   debug)r@   s    r   GetCloudSDKRootrB   M   s5     \\^$$(	

))&1	/r   c                      [        5       n [        R                  R                  U SS5      n[        R                  R	                  U5      (       d
  [        5       e[        R                  " SU5        U$ )zGets the directory of the GAE SDK directory in the SDK.

Raises:
  NoCloudSDKError: If there is no SDK root.
  NoAppengineSDKError: If the GAE SDK cannot be found.

Returns:
  str, The path to the root of the GAE SDK within the Cloud SDK.
platformgoogle_appenginezFound App Engine SDK root: %s)rB   ospathjoinisdirr*   r	   rA   )r@   gae_sdk_dirs     r   GetAppEngineSDKRootrK   ]   sT     (Xz3EF+	{	#	#

))+[9	r   c                     U " 5       R                  5       R                  5       R                  SS5      R                  SS5      SS $ )zGenerates a version id based off the current time.

Args:
  datetime_getter: A function that returns a datetime.datetime instance.

Returns:
  A version string based.
-r=   :N   )	isoformatlowerreplace)datetime_getters    r   GenerateVersionIdrT   p   sH     
		$	$	&	,	,	.	6	6sB	?	G	G	2

 r   c                 v    [         R                  " U R                  [        R                  R
                  5      6 $ )zHConverts a native-OS path to /-separated: os.path.join('a', 'b')->'a/b'.)	posixpathrH   splitrF   rG   sep)rG   s    r   ConvertToPosixPathrY   }   s"    	BGGKK0	11r   c                     U S;   a  U S-   $ U $ )zCConverts a App Engine region to the format used elsewhere in Cloud.>   
us-centraleurope-west1r   )regions    r   ConvertToCloudRegionr_      s    ,,C<Mr   c                 :    [        U5      nU R                  U5      $ )a)  Returns whether the given path should be skipped by the skip_files field.

A user can specify a `skip_files` field in their .yaml file, which is a list
of regular expressions matching files that should be skipped. By this point in
the code, it's been turned into one mega-regex that matches any file to skip.

Args:
  skip_files: A regular expression object for files/directories to skip.
  path: str, the path to the file/directory which might be skipped (relative
    to the application root)

Returns:
  bool, whether the file/dir should be skipped.
)rY   match)
skip_filesrG   s     r   
ShouldSkiprc      s    $ 
D	!$			$	r   c              #     #    S/nU(       GaZ  UR                  5       n[        [        R                  " [        R                  R                  X5      5      5      n[        U5       H  n[        R                  R                  X55      n[        R                  R                  X5      n[        R                  R                  U5      (       a/  [        X5      (       a  [        R                  " SU5        M  Uv   M  [        R                  R                  U5      (       d  M  [        X5      (       a  [        R                  " SU5        M  UR                  U5        M     U(       a  GMY  gg7f)zWalks a directory tree, returning all the files. Follows symlinks.

Args:
  base: The base path to search for files under.
  skip_files: A regular expression object for files/directories to skip.

Yields:
  Paths of files found, relative to base.
r=   z.Ignoring file [%s]: File matches ignore regex.z8Ignoring directory [%s]: Directory matches ignore regex.N)popsetrF   listdirrG   rH   sortedisfilerc   r	   inforI   append)baserb   dirscurrent_direntriesentrynamefullnames           r   FileIteratorrs      s      $((*K"**RWW\\$<=>GWW\\+-dd)h		!	!j''
((CT
J*77==""j''
((M ++d
 ! 	s   DE)AE)'E)c                     UnUnSn	 US-  nU " 5       u  pU
(       a  SU	4$ US::  a  U(       a
  [        5       eSU	4$ U" X5        [        R                  " U5        [        Xs-  U5      nMb  )aH  Calls a function multiple times, backing off more and more each time.

Args:
  func: f() -> (bool, value), A function that performs some operation that
    should be retried a number of times upon failure. If the first tuple
    element is True, we'll immediately return (True, value). If False, we'll
    delay a bit and try again, unless we've hit the 'max_tries' limit, in
    which case we'll return (False, value).
  retry_notify_func: f(value, delay) -> None, This function will be called
    immediately before the next retry delay.  'value' is the value returned
    by the last call to 'func'.  'delay' is the retry delay, in seconds
  initial_delay: int, Initial delay after first try, in seconds.
  backoff_factor: int, Delay will be multiplied by this factor after each
    try.
  max_delay: int, Maximum delay, in seconds.
  max_tries: int, Maximum number of tries (the first one counts).
  raise_on_timeout: bool, True to raise an exception if the operation times
    out instead of returning False.

Returns:
  What the last call to 'func' returned, which is of the form (done, value).
  If 'done' is True, you know 'func' returned True before we ran out of
  retries.  If 'done' is False, you know 'func' kept returning False and we
  ran out of retries.

Raises:
  TimeoutError: If raise_on_timeout is True and max_tries is exhausted.
NT   r   F)r-   timesleepmin)funcretry_notify_funcinitial_delaybackoff_factor	max_delay	max_triesraise_on_timeoutdelay	try_countvaluedones              r   RetryWithBackoffr      sy    > %)
%NI&KD5[A~	nE\e#JJu&	2E 	r   c                      [        XUSUU5      $ )au  Calls a function multiple times, with the same delay each time.

Args:
  callable_func: A function that performs some operation that should be
    retried a number of times upon failure.  Signature: () -> (done, value)
    If 'done' is True, we'll immediately return (True, value)
    If 'done' is False, we'll delay a bit and try again, unless we've
    hit the 'max_tries' limit, in which case we'll return (False, value).
  retry_notify_func: This function will be called immediately before the
    next retry delay.  Signature: (value, delay) -> None
    'value' is the value returned by the last call to 'callable_func'
    'delay' is the retry delay, in seconds
  delay: Delay between tries, in seconds.
  max_tries: Maximum number of tries (the first one counts).

Returns:
  What the last call to 'callable_func' returned, which is of the form
  (done, value).  If 'done' is True, you know 'callable_func' returned True
  before we ran out of retries.  If 'done' is False, you know 'callable_func'
  kept returning False and we ran out of retries.

Raises:
  Whatever the function raises--an exception will immediately stop retries.
ru   )r   )callable_funcrz   r   r~   s       r   RetryNoBackoffr      s    4 
-E1e#
% %r   c                  @    SR                  [        R                  5      $ )z%Gets the name of this source version.zGoogle-appcfg-{0})r8   r   CLOUD_SDK_VERSIONr   r   r   GetSourceNamer     s    		#	#F$<$<	==r   c                  P   / n U R                  [        R                  5        U R                  [        R                  R                  5       R                  5       5        SR                  S [        R                   5       5      nU R                  SU-  5        SR                  U 5      $ )zDetermines the value of the 'User-agent' header to use for HTTP requests.

Returns:
  String containing the 'user-agent' header value.
.c              3   N   #    U  H  n[         R                  " U5      v   M     g 7f)N)six	text_type).0is     r   	<genexpr>GetUserAgent.<locals>.<genexpr>#  s     G6FCMM!,,6Fs   #%z	Python/%s )
rk   r   CLOUDSDK_USER_AGENTr
   PlatformCurrentUserAgentFragmentrH   sysversion_info)product_tokenspython_versions     r   GetUserAgentr     s     . 223 	**224FFHI 88Gc6F6FGG.n45	.	!!r   c                   T    \ rS rSrSr\R
                  4S jrS
S jrS rS r	S r
Srg	)ClientDeployLoggingContexti)  aa  Context for sending and recording server rpc requests.

Attributes:
  rpcserver: The AbstractRpcServer to use for the upload.
  requests: A list of client_deployinfo.Request objects to include
    with the client deploy log.
  time_func: Function to get the current time in milliseconds.
  request_params: A dictionary with params to append to requests
c                 B    Xl         X l        X0l        X@l        / U l        g)aV  Creates a new AppVersionUpload.

Args:
  rpcserver: The RPC server to use. Should be an instance of HttpRpcServer
    or TestRpcServer.
  request_params: A dictionary with params to append to requests
  usage_reporting: Whether to actually upload data.
  time_func: Function to return the current time in millisecods
    (default time.time).
N)	rpcserverrequest_paramsusage_reporting	time_funcrequests)r#   r   r   r   r   s        r   r!   #ClientDeployLoggingContext.__init__4  s!     N(*NDMr   c                    U R                  5       n[        U5      n [        R                  " SR	                  XR
                  5      5        UR                  U R
                  5        U R                  R                  " U4SU0UD6nU R                  USUU5        U$ ! [         a-  nU R                  XR                  R                  UU5        e SnAff = f)z2Sends a request to the server, with common params.zSend: {0}, params={1}payload   N)GetCurrentTimeUseclenr	   rA   r8   r   updater   Send_RegisterReqestForLoggingr2   r:   r6   )r#   urlr   kwargsstart_time_usecrequest_size_bytesresulterrs           r   r   ClientDeployLoggingContext.SendI  s    --/OW	ii'..s4G4GHImmD''(~~""3BB6Bf
$$S#%79m 
$$S--*<*<o%79s   A>B 
C&(CCc                 R    [        [        U R                  5       S-  S-  5      5      $ )z)Returns the current time in microseconds.i  )introundr   )r#   s    r   r   -ClientDeployLoggingContext.GetCurrentTimeUsecZ  s#    uT^^%,t3455r   c           
          U R                  5       nU R                  R                  [        R                  " UUUUUS95        g)z7Registers a request for client deploy logging purposes.)rG   response_coder   end_time_usecr   N)r   r   rk   r   Request)r#   rG   r   r   r   r   s         r   r   4ClientDeployLoggingContext._RegisterReqestForLogging^  sA     ++-MMM*22#'#-/ 0r   c           	         U R                   (       d  [        R                  " S5        gU R                  5       n [        R
                  " UUUU R                  U[        R                  S9nU R                  SUR                  5       5        g! [         a/  n[        R                  " SR                  U5      5         SnAgSnAff = f)zLogs a client deployment attempt.

Args:
  runtime: The runtime for the app being deployed.
  start_time_usec: The start time of the deployment in micro seconds.
  success: True if the deployment succeeded otherwise False.
zSkipping usage reporting.N)runtimer   r   r   successsdk_versionz/api/logclientdeployz.Exception logging deploy info continuing - {0})r   r	   rj   r   r   ClientDeployInfoExternalr   r   r   r   ToYAMLBaseExceptionrA   r8   )r#   r   r   r   r   rj   es          r   LogClientDeploy*ClientDeployLoggingContext.LogClientDeployi  s     	hh*+++-M
L77)%==..0d ii&6 L	ii@GGJKKLs   AB 
C%C  C)r   r   r   r   r   Nr<   )r   r   r   r   r   rv   r!   r   r   r   r   r   r   r   r   r   r   )  s*     	*"6	0Lr   r   c                   $    \ rS rSrSrS rS rSrg)	RPCServeri  zThis wraps the underlying RPC server so we can make a nice error message.

This will go away once we switch to just using our own http object.
c                     Xl         g)zJConstruct a new rpc server.

Args:
  original_server: The server to wrap.
N_server)r#   original_servers     r   r!   RPCServer.__init__  s	     #Lr   c                 F    U R                   R                  " U0 UD6n[        R                  " SU5        U$ ! [        R
                  R                   aK  n[        US5      (       a  UR                  5       nOSn[        R                  " [        XES95         S nAg S nAff = f)NzGot response: %sreadr=   )r7   )r   r   r	   rA   r   error	HTTPErrorhasattrr   r   reraiser2   )r#   argsr   responser   r7   s         r   r   RPCServer.Send  s    
1""D3F3h	ii"H-o<<!! 1	F		vvx!/001s   47 B ABB r   N)r   r   r   r   r   r!   r   r   r   r   r   r   r     s    
#1r   r   )ru      <      T)   r   )*r   
__future__r   r   r   datetimerF   rV   r   rv   googlecloudsdk.appengine.apir   googlecloudsdk.corer   r   r	   googlecloudsdk.core.utilr
   r   	six.movesr   r   r   r   r*   r-   r2   rB   rK   nowrT   rY   r_   rc   rs   r   r   r   r   objectr   r   r   r   r   <module>r      s     ( &  '  	  
  : & * # . 
 *J *OU O4e 49% 9<5 <	u 	 & '/&7&7&;&; 
2
 ,B 67BF.3b%<>
"*VL VLr1 1r   