
    g$                         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J	r	  SSKJ
r
  SSKJr  SS	KJr  SSKr " S
 S\5      rg)a  This module implements update checking and notification to the user.

It provides a context manager around the cache file that stores information
about the last update check.  The general process is as follows:

1) This stores the last time an update check occurred, so the check will only
   be done if the update check frequency has expired.
2) When an update check is done, all notifications in the latest snapshot are
   queried to see if their condition matches the current state of the SDK.  Any
   notifications that match are "activated" and cached.
3) Every time a command is run, Notify() is called to notify the user of
   available updates.  It loops over the activated notifications and determines
   if any of the triggers match the current command invocation.  If there is a
   match, the notification is printed and the last nag time is recorded for that
   particular notification.  At most one notification is printed per command.
   The priority is determined by the order the notifications are registered
   in the component snapshot.
    )absolute_import)division)unicode_literalsN)config)log)schemas)filesc                   t    \ rS rSrSrSrS rS rS rS r	S r
S	 rS
 rS rS rS rSS jrS rS rS rSrg)UpdateCheckData3   zBA class to hold update checking data and to perform notifications.iQ c                     [         R                  " 5       R                  U l        SU l        U R                  5       U l        g )NF)r   Pathsupdate_check_cache_path_last_update_check_file_dirty	_LoadData_dataselfs    /lib/googlecloudsdk/core/updater/update_check.py__init__UpdateCheckData.__init__8   s+    #)<<>#I#ID DK!DJ    c                    [         R                  R                  U R                  5      (       d  [        R
                  R                  0 5      $ [        R                  " U R                  5      n [        R                  " U5      n[        R
                  R                  U5      $ ! [         a8    [        R                  " S5        [        R
                  R                  0 5      s $ f = f)z%Deserializes data from the json file.zDFailed to parse update check cache file.  Using empty cache instead.)ospathisfiler   r   LastUpdateCheckFromDictionaryr	   ReadFileContentsjsonloads
ValueErrorr   debug)r   raw_datadatas      r   r   UpdateCheckData._LoadData=   s    77>>$6677$$33B77%%d&B&BCH8ZZ!d$$33D99 8	ii ! "$$33B778s   /4B$ $?C&%C&c                     U R                   (       d  g[        R                  " U R                  [        R
                  " U R                  R                  5       5      5        SU l         g)z!Serializes data to the json file.NF)r   r	   WriteFileContentsr   r!   dumpsr   ToDictionaryr   s    r   	_SaveDataUpdateCheckData._SaveDataK   sC    ;;	D88 JJtzz'>'>'@ACDKr   c                     U $ N r   s    r   	__enter__UpdateCheckData.__enter__S   s    Kr   c                 $    U R                  5         g r/   )r,   )r   argss     r   __exit__UpdateCheckData.__exit__V   s    NNr   c                 .    U R                   R                  $ )zGets the revision of the snapshot from the last update check.

Returns:
  long, The revision of the last checked snapshot.  This is a long int but
    formatted as an actual date in seconds (i.e 20151009132504). It is *NOT*
    seconds since the epoch.
)r   last_update_check_revisionr   s    r   LastUpdateCheckRevision'UpdateCheckData.LastUpdateCheckRevisionY   s     ::000r   c                 .    U R                   R                  $ )zGets the time of the last update check as seconds since the epoch.

Returns:
  int, The time of the last update check in seconds since the epoch.
)r   last_update_check_timer   s    r   LastUpdateCheckTime#UpdateCheckData.LastUpdateCheckTimec   s     ::,,,r   c                 Z    [         R                   " 5       U R                  R                  -
  $ )znGets the number of seconds since we last did an update check.

Returns:
  int, The amount of time in seconds.
)timer   r<   r   s    r   SecondsSinceLastUpdateCheck+UpdateCheckData.SecondsSinceLastUpdateCheckk   s     99;::::r   c                 D    U R                  5       [        R                  :  $ )zChecks if it is time to do an update check.

Returns:
  True, if enough time has elapsed and we should perform another update
  check.  False otherwise.
)rA   r   !UPDATE_CHECK_FREQUENCY_IN_SECONDSr   s    r   ShouldDoUpdateCheck#UpdateCheckData.ShouldDoUpdateChecks   s#     ,,.==> ?r   c                     [        U R                  R                   Vs/ s H"  nUR                  R                  (       d  M   UPM$     sn5      $ s  snf )zReturns whether we already know about updates that are available.

Returns:
  bool, True if we know about updates, False otherwise.
)boolr   notifications	conditioncheck_components)r   notifications     r   UpdatesAvailable UpdateCheckData.UpdatesAvailable}   sJ     )-)A)A)A!!22 	)A   s   AAc                    U(       d  U R                  5       UR                  :w  a  [        R                  " S5        [        R
                  R                  n[        R
                  R                  n/ nUR                  R                  nU HX  nUR                  R                  XEU5      (       d  M&  [        R                  " SUR                  5        UR                  U5        MZ     X`R                  l        U R                  5         [        R                  " 5       U R                  l        UR                  U R                  l        SU l        g)a  Sets that we just did an update check and found the given snapshot.

If the given snapshot is different than the last one we saw, refresh the set
of activated notifications for available updates for any notifications with
matching conditions.

You must call Save() to persist these changes or use this as a context
manager.

Args:
  snapshot: snapshots.ComponentSnapshot, The latest snapshot available.
  component_updates_available: bool, True if there are updates to components
    we have installed.  False otherwise.
  force: bool, True to force a recalculation of whether there are available
    updates, even if the snapshot revision has not changed.
zUpdating notification cache...zActivating notification: [%s]TN)r9   revisionr   r$   r   INSTALLATION_CONFIGversionsdk_definitionrI   rJ   Matchesidappendr   _CleanUpLastNagTimesr@   r<   r8   r   )	r   snapshotcomponent_updates_availableforcecurrent_versioncurrent_revision	activatedpossible_notificationsrL   s	            r   SetFromSnapshotUpdateCheckData.SetFromSnapshot   s    " ,,.(2C2CC	ii0122::o33<<i'66DD0,!!))/JL L
))3\__
E


<
(	 1 "+jj
!(,		DJJ%,4,=,=DJJ)DKr   c           
         [         R                  " S5        [        R                  " S[        R                  " SSSSS5      [        R
                  " SSS9[        R                  " SSS5      S9nU/U R                  l        U R                  5         [        R                  " 5       U R                  l        SU R                  l        S	U l        g)
am  Sets that we just did an update check and found a new schema version.

An incompatible schema version means there are definitely updates available
but we can't read the notifications to correctly notify the user.  This will
install a default notification for the incompatible schema.

You must call Save() to persist these changes or use this as a context
manager.
z<Incompatible schema found.  Activating default notification.incompatibleNFi:	 )	frequencycommand_regex)rU   rJ   triggerrL   r   T)r   r$   r   NotificationSpec	ConditionTriggerNotificationr   rI   rW   r@   r<   r8   r   )r   notification_specs     r   SetFromIncompatibleSchema)UpdateCheckData.SetFromIncompatibleSchema   s     IILM  00##D$dEB&E))$d;	 !22DJJ(,		DJJ%,-DJJ)DKr   c                   ^ U R                   R                   Vs/ s H  oR                  PM     snm[        U4S j[        R
                  " U R                   R                  5       5       5      U R                   l        gs  snf )zClean the map holding the last nag times for each notification.

If a notification is no longer activate, it is removed from the map.  Any
notifications that are still activated have their last nag times preserved.
c              3   >   >#    U  H  u  pUT;   d  M  X4v   M     g 7fr/   r0   ).0namevalueactivated_idss      r   	<genexpr>7UpdateCheckData._CleanUpLastNagTimes.<locals>.<genexpr>   s&      &G}$ TMGs   
N)r   rI   rU   dictsix	iteritemslast_nag_times)r   nrr   s     @r   rW   $UpdateCheckData._CleanUpLastNagTimes   s`     $(::#;#;<#;aTT#;<M &"}}TZZ-F-FG& 	& 	JJ =s   A?c                 H   [         R                  R                  5       (       a#  [         R                  R                  5       (       d  gU R                  R
                   H  nUR                  nU R                  R                  R                  US5      nUR                  R                  XA5      (       d  MW  [         R                  R                  UR                  R                  5       5        [        R                  " 5       U R                  R                  U'   SU l          g   g)an  Notify the user of any available updates.

This should be called for every command that is run.  It does not actually
do an update check, and does not necessarily notify the user each time.  The
user will only be notified if there are activated notifications and if the
trigger for one of the activated notifications matches.  At most one
notification will be printed per command.  Order or priority is determined
by the order in which the notifications are registered in the component
snapshot file.

Args:
  command_path: str, The '.' separated path of the command that is currently
    being run (i.e. gcloud.foo.bar).
Nr   T)r   outisattystatusr   rI   rU   rx   getre   rT   writerL   NotificationMessager@   r   )r   command_pathrL   rp   last_nag_times        r   NotifyUpdateCheckData.Notify   s      77>>3::#4#4#6#6

00__djj//33D!<m 
			%	%m	B	B

22FFHI*.))+

!!$' 1r   )r   r   r   N)F)__name__
__module____qualname____firstlineno____doc__rD   r   r   r,   r1   r5   r9   r=   rA   rE   rM   r_   rk   rW   r   __static_attributes__r0   r   r   r   r   3   sR    J&+#"
81-;?	%N6'r   r   )r   
__future__r   r   r   r!   r   r@   googlecloudsdk.corer   r   googlecloudsdk.core.updaterr   googlecloudsdk.core.utilr	   rv   objectr   r0   r   r   <module>r      s;    & '  '  	  & # / * 
Af Ar   