o
    s                    @   s   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
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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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#m'Z' ddl(Z(ddl)m*Z* dZ+i ddddd dd!dd"dd#dd$dd%dd&dd'e+d(e+d)e+d*e+d+e+d,dd-dd.ddddd/Z,g d0Z-d1d2gZ.d3Z/d4Z0d5d6 Z1d7d8 Z2d9d: Z3G d;d< d<ej4Z4G d=d> d>e4Z5G d?d@ d@e4Z6G dAdB dBe4Z7G dCdD dDe4Z8G dEdF dFe4Z9G dGdH dHe4Z:G dIdJ dJe4Z;G dKdL dLe4Z<G dMdN dNe4Z=G dOdP dPe4Z>G dQdR dRe4Z?dSdT Z@G dUdV dVeAZBdWdX ZCdYdZ ZDd`d[d\ZEdad^d_ZFdS )bzFHigher level functions to support updater operations at the CLI level.    )absolute_import)division)unicode_literalsN)
argv_utils)config)
exceptions)execution_utils)log)metrics)
properties)yaml)console_attr)
console_io)progress_tracker)resource_printer)universe_descriptor)
installers)local_state)python_manager)release_notes)	snapshots)update_check)encoding)files)	platforms)mapa  The standalone App Engine SDKs are no longer distributed through the Google Cloud CLI
(however, the appcfg and dev_appserver commands remain the official and
supported way of using App Engine from the command line).  If you want to
continue using these tools, they are available for download from the official
App Engine download page here:
    https://cloud.google.com/appengine/downloads
appzapp-engine-go-linux-x86zapp-engine-go-linux-x86_64zapp-engine-go-darwin-x86zapp-engine-go-darwin-x86_64zapp-engine-go-windows-x86zapp-engine-go-windows-x86_64computednszgae-javaz
gae-pythonzgae-gozgae-python-launcher-maczgae-python-launcher-winzpkg-corezpkg-javaz
pkg-python)zpkg-gopreviewsql)zcompletion.bash.inczcompletion.zsh.inczpath.bash.inczpath.fish.inczpath.zsh.inczgcfilesys.bash.inczgcfilesys.zsh.inczbundled-python3zbundled-python3-unixz{This command is running using a bundled installation of Python. If you remove it, you may have no way to run this command.
z`Once started, canceling this operation may leave your SDK installation in an inconsistent state.c                  C   s4   t j } | t jjfv rtd td d S d S )NzTo remove bundled python component please re-run this command after setting CLOUDSDK_PYTHON env var to preferred system python.   )r   OperatingSystemCurrentMACOSXr	   errorsysexit)
current_os r)   G/tmp/google-cloud-sdk/lib/googlecloudsdk/core/updater/update_manager.py_HaltIfBundledPythonUnixn   s   
r+   c                 C   s   t tttt| @ dkS )zFReturn true if components list contains 'bundled python' component(s).r!   )lenlistsetBUNDLED_PYTHON_COMPONENTS
componentsr)   r)   r*   _ContainsBundledPythonx   s   r2   c                    sz   |   }|jdur|  S z' fdd|jD D ]}|  }| j|jv r/|jjr/|   W S qW |  S    Y |  S )a  Return most accurate VersionString for component with id comp_id.

  Component versions become stale in the case where only the architecture
  specific component has content. In these cases show the version from the
  architecture specific component, not the parent component.

  Args:
    component: updater.local_state.InstallationManifest of component to get
      VersionString of.
    installed_components: map of str to InstallationManifest of installed
      components.

  Returns:
    str, Most accurate VersionString for comp_id.
  Nc                    s   g | ]
}| v r | qS r)   r)   ).0dinstalled_componentsr)   r*   
<listcomp>   s
    z%_GetVersionString.<locals>.<listcomp>)ComponentDefinitiondataVersionStringdependenciesidplatformarchitectures)	componentr6   comp_defdepdep_defr)   r5   r*   _GetVersionString}   s    



rC   c                   @      e Zd ZdZdS )Errorz-Base exception for the update_manager module.N__name__
__module____qualname____doc__r)   r)   r)   r*   rE          rE   c                   @   rD   )InvalidCWDErrorzDError for when your current working directory prevents an operation.NrF   r)   r)   r)   r*   rL      rK   rL   c                   @   rD   )UpdaterDisabledErrorz;Error for when an update is attempted but it is disallowed.NrF   r)   r)   r)   r*   rM      rK   rM   c                   @   rD   )InvalidComponentErrorzCError for when a given component id is not valid for the operation.NrF   r)   r)   r)   r*   rN      rK   rN   c                   @   rD   )GcloudNotFoundErrorz2Error for when gcloud cannot be found on the path.NrF   r)   r)   r)   r*   rO      rK   rO   c                   @   rD   )NoBackupErrorzBError for when you try to restore a backup but one does not exist.NrF   r)   r)   r)   r*   rP      rK   rP   c                   @   rD   )ReinstallationFailedErrorz,Error for when performing a reinstall fails.NrF   r)   r)   r)   r*   rQ      rK   rQ   c                   @   rD   )MissingRequiredComponentsErrorzCError for when components are required, but you don't install them.NrF   r)   r)   r)   r*   rR      rK   rR   c                       s    e Zd ZdZ fddZ  ZS )MissingUpdateURLErrorz3Error for when the URL for the manifest is not set.c                    s   t t| d d S )NzThe update action could not be performed because the component manager is incorrectly configured.  Please re-install the Google Cloud CLI and try again.)superrS   __init__self	__class__r)   r*   rU      s   
zMissingUpdateURLError.__init__)rG   rH   rI   rJ   rU   __classcell__r)   r)   rX   r*   rS      s    rS   c                   @   rD   )MismatchedFixedVersionsErrorzLError for when you have pinned a version but you ask for a different one.
  NrF   r)   r)   r)   r*   r[          r[   c                   @   rD   )PostProcessingErrorz)Error for when post processing failed.
  NrF   r)   r)   r)   r*   r]      r\   r]   c                   @   rD   )NoRegisteredRepositoriesErrorz3Error for when there are no repositories to remove.NrF   r)   r)   r)   r*   r^      s    r^   c                 C   s   t dd | D dd dS )zCFilters out top level components with no installable ComponentData.c                 S   s   g | ]	}|j d ur|qS N)r9   )r3   compr)   r)   r*   r7      s    z(FilterMetaComponents.<locals>.<listcomp>c                 S      | j jS r_   detailsdisplay_namecr)   r)   r*   <lambda>       z&FilterMetaComponents.<locals>.<lambda>key)sortedr0   r)   r)   r*   FilterMetaComponents   s   rl   c                   @   s  e Zd ZdZdZdZeejj	ej
jZedd ZedcddZed	d
 ZeddddZ		deddZdd Zdd ZdfddZdgddZdd Z	dhddZdcddZd d! Zdhd"d#Zdid%d&Zdid'd(Zddd)d*Zddd+d,Zdjd-d.Z d/d0 Z!d1d2 Z"dhd3d4Z#d5d6 Z$d7d8 Z%		djd9d:Z&d;d< Z'd=d> Z(dkd?d@Z)		dldAdBZ*dCdD Z+dEdF Z,dmdGdHZ-dhdIdJZ.dhdKdLZ/dMdN Z0dOdP Z1dQdR Z2dSdT Z3dUdV Z4dWdX Z5dcdYdZZ6d[d\ Z7dcd]d^Z8d_d` Z9dhdadbZ:dS )nUpdateManagerz;Main class for performing updates for the Google Cloud CLI.binzcomponents-v{0}.jsonc                  C   s    t jjj } | r| dS g S )zGets the currently registered repositories as a list.

    Returns:
      [str], The list of registered repos or [] if there are none.
    ,)r   VALUEScomponent_manageradditional_repositoriesGetsplit)reposr)   r)   r*   GetAdditionalRepositories   s   
z'UpdateManager.GetAdditionalRepositoriesNc                 C   s$   t j }t|dd}|| ||S )@  Installs the given components if necessary and then restarts gcloud.

    Args:
      components: [str], The components that must be installed.
      msg: str, A custom message to print.
      command: str, the command to run, if not `gcloud`

    Returns:
      bool, True if the components were already installed.  If installation must
      occur, this method never returns because gcloud is reinvoked after the
      update is done.

    Raises:
      MissingRequiredComponentsError: If the components are not installed and
      the user chooses not to install them.
    Fplatform_filterwarn)r   Platformr#   rm   _EnsureInstalledAndRestart)r1   msgcommandr=   managerr)   r)   r*   EnsureInstalledAndRestart   s   
z'UpdateManager.EnsureInstalledAndRestartc                  C   sX   t jjstjjj rt	d dS t
 } |  W  d   S 1 s%w   Y  dS )zReturns True if updates are available, False otherwise.

    Returns:
      bool, True if updates are available, False otherwise.
    SDK update checks are disabled.FN)r   INSTALLATION_CONFIGdisable_updaterr   rp   rq   disable_update_checkGetBoolr	   debugr   UpdateCheckDataUpdatesAvailable)last_update_checkr)   r)   r*   r     s   

$zUpdateManager.UpdatesAvailableFc                 C   sL   t jjstjjj rt	d dS t
j }t|dd}|j| |d dS )p  Checks to see if a new snapshot has been released periodically.

    This method can be called as often as you'd like.  It will only actually
    check the server for updates if a certain amount of time has elapsed since
    the last check (or if force is True).  If updates are available, to any
    installed components, it will print a notification message.

    Args:
      command_path: str, The '.' separated path of the command that is currently
        being run (i.e. gcloud.foo.bar).
      force: bool, True to force a server check for updates, False to check only
        if the update frequency has expired.
    r   NFrx   force)r   r   r   r   rp   rq   r   r   r	   r   r   r{   r#   rm   _PerformUpdateCheck)command_pathr   r=   r   r)   r)   r*   PerformUpdateCheck#  s   

z UpdateManager.PerformUpdateCheckc                 C   s  || _ | j st j| _ | j st t| j | _ |du r&tj	j
j  }|s/tj	j
j }|r9|r9td| t }|sHt sH| |}|sQtj	j
j }|sVt tj| j | _ || _|| _tjddd| _|| _|  | _ tj	j
j! }|| _"|| _#dS )a  Creates a new UpdateManager.

    Args:
      sdk_root: str, The path to the root directory of the Cloud SDK is
        installation.  If None, the updater will search for the install
        directory based on the current directory.
      url: str, The URL to get the latest component snapshot from.  If None,
        the default will be used.
      platform_filter: platforms.Platform, A platform that components must match
        in order to be considered for any operations.  If None, only components
        without OS or architecture filters will match.
      warn: bool, True to warn about overridden configuration like an alternate
        snapshot file, fixed SDK version, or additional repo.  Should be set
        to False when using this class for background operations like checking
        for updates so the user only sees the warnings when they are actually
        dealing directly with the component manager.
      skip_compile_python: bool, if True the UpdateManager will not pre compile
      installed python files.

    Raises:
      local_state.InvalidSDKRootError: If the Cloud SDK root cannot be found.
      MissingUpdateURLError: If we don't know what manifest to download.
    Nz.You are using an overridden snapshot URL: [%s]F)replace_whitespacedrop_whitespace)$_UpdateManager__sdk_rootr   Pathssdk_rootr   InvalidSDKRootErrorr   Decoder   rp   rq   disable_warningr   snapshot_urlrs   r	   warningGetUniverseDomainIsDefaultUniverseGetUniverseSnapshotURLoriginal_snapshot_urlrS   ospathrealpath_UpdateManager__base_url_UpdateManager__platform_filtertextwrapTextWrapper_UpdateManager__text_wrapper_UpdateManager__warn_EnableFallback_UpdateManager__enable_fallbackfixed_sdk_version_UpdateManager__fixed_version#_UpdateManager__skip_compile_python)rW   r   urlry   rz   skip_compile_pythonuniverse_domainfixed_versionr)   r)   r*   rU   =  s<   


zUpdateManager.__init__c                 C   s   d}| d|S )z:Get the snapshot URL based on the current universe domain.zJhttps://storage.googleapis.com/cloud-cli-release/release/components-2.jsonzgoogleapis.com)replace)rW   r   addressr)   r)   r*   r     s   z$UpdateManager.GetUniverseSnapshotURLc                 C   s&   | j o| j jtjjko| j jtjjkS r_   )r   operating_systemr   r"   r$   architectureArchitecturearmrV   r)   r)   r*   r     s
   zUpdateManager._EnableFallback c                 C   s*   |r| j |}||d  |  dS )a  Writes the given message to the out stream with a new line.

    Args:
      stream:  The output stream to write to.
      msg: str, The message to write.
      word_wrap: bool, True to enable nicer word wrapper, False to just print
        the string as is.
    
N)r   fillwriteflush)rW   streamr}   	word_wrapr)   r)   r*   __Write  s   	zUpdateManager.__WriteTc                 C   sj   d}z
t jt }W n ty   td Y nw |r$t| j	|s&dS |r,|s,dS t
dj| j	d)a  Ensures that the CWD is valid for the update being performed.

    Args:
      in_place: bool, Whether we're performing an in-place update vs. replacing
        with another install state.
      has_components_to_remove: bool, Whether the update operation involves
        removing any components. Affects whether we can perform an in-place
        update from inside the root dir.

    Raises:
      InvalidCWDError: If the command is run from a directory within the SDK
        root that would cause problems when updating.
    NzHCould not determine CWD, assuming detached directory not under SDK root.zYour current working directory is inside the Google Cloud CLI install root: {root}.  In order to perform this update, run the command from outside of this directory.)root)r   r   r   
file_utilsGetCWDOSErrorr	   r   IsDirAncestorOfr   rL   format)rW   in_placehas_components_to_removecwdr)   r)   r*   	_CheckCWD  s   	zUpdateManager._CheckCWDc                 C   s6   t  }tj|j|j|}tj|rt	|S dS )zChecks if mapping files are present and loads them for further use.

    Args:
      filename: str, The full filename (with .yaml extension) to be loaded.

    Returns:
      Loaded YAML if mapping files are present, None otherwise.
    N)
r   r   r   r   joinr   CLOUDSDK_STATE_DIRisfiler   	load_path)rW   filenamepathsmapping_pathr)   r)   r*   _GetMappingFile  s   	
zUpdateManager._GetMappingFilec           
         s  d}dd}dd}dd}|| }	|r' fdd|D  fdd|D ||kr9fddt   D }nfd	d|D } fd
d|D }|rW|	jd|d}	|s[|sc|dj|	d7 }rs|djdtjjd7 }r|djdd7 }|S )a  Returns error message containing correct command mapping.

    Checks the user-provided command to see if it maps to one we support for
    their package manager. If it does, compute error message to let the user
    know why their command did not work and provide them with an alternate,
    accurate command to run. If we do not support the given command/component
    combination for their package manager, provide user with instructions to
    change their package manager.

    Args:
      command: str, Command from user input, to be mapped against
        commands_mapping.yaml
      commands_map: dict, Contains mappings from commands_mapping.yaml
      components_map: dict, Contains mappings from components_mapping.yaml
      components: str list, Component from user input, to be mapped against
        component_commands.yaml

    Returns:
      str, The compiled error message.
    r   unavailable
update-allNc                    s   g | ]}| vr|qS r)   r)   r3   r?   components_mapr)   r*   r7     
    z8UpdateManager._ComputeMappingMessage.<locals>.<listcomp>c                    s   g | ]}  |kr|qS r)   )getr   )r   r   r)   r*   r7     s
    c                    s   g | ]}| kr|qS r)   r)   r   )r   r)   r*   r7     r   c                    s    g | ]}|vr| vr|qS r)   r)   r   )not_componentsunavailable_componentsr)   r*   r7     s    c                    s   g | ]} | qS r)   r)   r   r   r)   r*   r7     s     )packagez
You cannot perform this action because the Google Cloud CLI component manager 
is disabled for this installation. You can run the following command 
to achieve the same result for this installation: 

{correct_command}

)correct_commandz
The {component} component(s) is unavailable through the packaging system 
you are currently using. Please consider using a separate installation 
of the Google Cloud CLI created through the default mechanism described at: 

{doc_url} 

, )r?   doc_urlz/"{component}" are not valid component name(s).
)r?   )r.   valuesr   r   r   r   documentation_url)
rW   r~   commands_mapr   r1   final_message
update_allmapped_componentsmapped_packagesr   r)   )r   r   r   r   r*   _ComputeMappingMessage  sf   



	z$UpdateManager._ComputeMappingMessagec                 C   sh   dj tjjd}tjjr2|st|| jdd}| jdd}|r"|s&t|| ||||}t|dS )a  Checks if updater is disabled. If so, raises UpdaterDisabledError.

    The updater is disabled for installations that come from other package
    managers like apt-get or if the current user does not have permission
    to create or delete files in the SDK root directory. If disabled, raises
    UpdaterDisabledError either with the default message, or an error message
    from _ComputeMappingMessage if a command was passed in.

    Args:
      components: str list, Component from user input, to be mapped against
        component_commands.yaml
      command: str, Command from user input, to be mapped against
        command_mapping.yaml

    Raises:
      UpdaterDisabledError: If the updater is disabled.
    zYou cannot perform this action because this Google Cloud CLI installation is managed by an external package manager.
Please consider using a separate installation of the Google Cloud CLI created through the default mechanism described at: {doc_url}
)r   zcommand_mapping.yaml)r   zcomponent_mapping.yamlN)r   r   r   r   r   rM   r   r   )rW   r1   r~   default_messager   r   mapping_messager)   r)   r*   _CheckIfDisabledAndThrowError0  s"   z+UpdateManager._CheckIfDisabledAndThrowErrorc                 C   s   t | jS r_   )r   InstallationStater   rV   r)   r)   r*   _GetInstallState]  s   zUpdateManager._GetInstallStatec                 C   s   | j }|r| jr| j|krtd| j|n| jr)| jr&td| j | j}|rG|d}tj	
|d d tj| |d< d|}tjjj }|rh| jra|dD ]}td| qXd||g}|S )a  Get the snapshot URL we shoould download based on any override versions.

    This starts with the configured URL (or comma separated URL list) and
    potentially modifies it based on the version.  If a version is specified,
    it is converted to the fixed version specific snapshot.  If the SDK is set
    to use a fixed version, that is then used.  If neither, the original URL
    is used.

    Args:
      version: str, The Cloud SDK version to get the snapshot for.

    Raises:
      MismatchedFixedVersionsError: If you manually specify a version and you
        are fixed to a different version.

    Returns:
      str, The modified snapshot URL.
    zYou have configured your Google Cloud CLI installation
to be fixed to version [{0}] but are attempting to install components at
version [{1}].  To clear your fixed version setting, run:
    $ gcloud config unset component_manager/fixed_sdk_versionzTYou have configured your Google Cloud CLI installation to be fixed to version [{0}].ro   r   /z3You are using additional component repository: [%s])r   r   r[   r   r   r	   r   rt   r   r   dirnamerm   VERSIONED_SNAPSHOT_FORMATr   r   rp   rq   rr   rs   )rW   versionr   urlsru   repor)   r)   r*   _GetEffectiveSnapshotURL`  s>   


z&UpdateManager._GetEffectiveSnapshotURLunknownc                 C   sh   | j |d}ztjj|dd|iW S  tjy3   |r&td|  | j	r2td| j	  w )N)r   ro   r   zThe component listing for Google Cloud CLI version [{0}] could not be found.  Make sure this is a valid archived Google Cloud CLI version.zYou have configured your Google Cloud CLI installation to be fixed to version [{0}]. Make sure this is a valid archived Google Cloud CLI version.)
r   r   ComponentSnapshotFromURLsrt   URLFetchErrorr	   r%   r   r   )rW   r   r   effective_urlr)   r)   r*   _GetLatestSnapshot  s*   	z UpdateManager._GetLatestSnapshotc                 C   s.   |   }| j||d}|j|| jd}||fS )Nr   r   ry   )r   r   DiffCurrentStater   )rW   r   r   install_statelatest_snapshotdiffr)   r)   r*   _GetStateAndDiff  s   zUpdateManager._GetStateAndDiffc                 C   sT   |   }i }| }t|D ]\}}| }|js|jr |s qt||||< q|S )zGet the current version for every installed component.

    Args:
      include_hidden: bool, include hidden components.

    Returns:
      {str:str}, A mapping from component id to version string.
    )r   InstalledComponentssix	iteritemsr8   is_configuration	is_hiddenrC   )rW   include_hiddencurrent_stateversionsr6   component_idr?   component_defr)   r)   r*   GetCurrentVersionsInformation  s   	
z+UpdateManager.GetCurrentVersionsInformationc              	   C   s   t  @}|s| r7td z| jtjd\}}|j|j	t
| |d W n tjy6   |  Y nw || W d   dS 1 sGw   Y  dS )r   zChecking for updates...r   r   N)r   r   ShouldDoUpdateCheckr	   r   r   r   UPDATE_MANAGER_COMMAND_PATHSetFromSnapshotlatestboolAvailableUpdatesr   IncompatibleSchemaVersionErrorSetFromIncompatibleSchemaNotify)rW   r   r   r   _r   r)   r)   r*   r     s   



"z!UpdateManager._PerformUpdateCheckc                 C   sh   |r|   \}}d}n|  \}}}|sdd |D }tjjj tjjjjkr/dd |D }|||fS )a  Lists all of the components and their current state.

    This pretty prints the list of components along with whether they are up
    to date, require an update, etc.

    Args:
      show_hidden: bool, include hidden components.
      only_local_state: bool, only return component information for local state.

    Returns:
      The list of snapshots.ComponentDiffs (or snapshots.ComponentInfos if
      only_local_state is True) for all components that are not hidden.
    Nc                 S      g | ]}|j s|qS r)   )r  r3   rf   r)   r)   r*   r7         z&UpdateManager.List.<locals>.<listcomp>c                 S   r  r)   )gdu_onlyr  r)   r)   r*   r7     r  )_GetPrintListOnlyLocal_GetPrintListWithDiffr   rp   corer   rs   default)rW   show_hiddenonly_local_stateto_printcurrent_versionlatest_versionr)   r)   r*   List  s   

zUpdateManager.Listc                    s   |   }| j| jd}|  r1tdd |D  | j| jd} fdd|D }|| tj	j
}| tjd|  ||fS )zHelper method that gets a list of locally installed components to print.

    Returns:
      List of snapshots.ComponentInfos for the List method as well as the
      current version string.
    r   c                 s   s    | ]}|j V  qd S r_   r<   r  r)   r)   r*   	<genexpr>  s    z7UpdateManager._GetPrintListOnlyLocal.<locals>.<genexpr>c                 3   s    | ]
}|j  vr|V  qd S r_   r#  r  
native_idsr)   r*   r$    s    +
Your current Google Cloud CLI version is: )r   SnapshotCreateComponentInfosr   r   r.   DARWIN_X86_64extendr   r   r   _UpdateManager__Writer	   status)rW   r   r  darwin_x86_64_allto_print_x86_64r   r)   r%  r*   r    s"   
z$UpdateManager._GetPrintListOnlyLocalc              
   C   s   z
| j dd\}}W n tjy' } z| | g ddfW  Y d}~S d}~ww | js-dnd}| j||d\}}| |  |  |	  }|||fS )zHelper method that computes a diff and returns a list of diffs to print.

    Returns:
      List of snapshots.ComponentDiffs for the List method as well as the
      current and latest version strings.
    zcomponents.listr
  Nz!The latest available version is: 
latest_msg)
r   r   r  _ReinstallOnErrorr   _PrintVersionsr  RemovedAvailableToInstallUpToDate)rW   r  r   er1  r   r!  r  r)   r)   r*   r    s(   


z#UpdateManager._GetPrintListWithDiffc                 C   sP   t jj}|jj}| tjd|  |r|r| tj||  | tj ||fS )ah  Prints the current and latest version.

    Args:
      diff: snapshots.ComponentSnapshotDiff, The snapshot diff we are working
        with.
      latest_msg: str, The message to print when displaying the latest version.
        If None, nothing about the latest version is printed.

    Returns:
      (str, str), The current and latest version strings.
    r'  )r   r   r   r  r,  r	   r-  )rW   r   r1  r   r!  r)   r)   r*   r3  2  s   zUpdateManager._PrintVersionsc              	   C   sl   i }|D ]/}z t j| j|}t j|sW qtt|	 }|||< W q t
y3   d||< Y qw |S )zCreates the sha256 checksums of files.

    Args:
      shell_rc_files: list, A list of files to get the sha256 checksums.
    Returns:
      sha256dict, dictionary of sha256 file sums.
    r   )r   r   r   r   existshashlibsha256r   ReadBinaryFileContents	hexdigestr   )rW   shell_rc_files
sha256dictnamefpathr:  r)   r)   r*   _HashRcfilesI  s"   	zUpdateManager._HashRcfilesc                 C   sH   ddj |dg}g d}dj d|d|d}tj||tjd d	S )
zPrints info about components we are going to install or remove.

    Args:
      components: list(schemas.Component), The components that are going to be
        acted on.
      action: str, The verb to print for this set of components.
    boxz*title="These components will be {action}.")action)z*details.display_name:label=Name:align=leftz0version.version_string:label=Version:align=rightz:data.size.size(zero="",min=1048576):label=Size:align=rightztable[{attributes}]({columns})ro   )
attributescolumns)outN)r   r   r   Printr	   r-  )rW   r1   rC  rD  rE  fmtr)   r)   r*   _PrintPendingActiona  s   	
z!UpdateManager._PrintPendingActionc              	   C   s   i }t |D ]>\}}dj||jjd}	tj|	tj||o"|t|d kd}
||j	|
j
d}|||j	< W d   n1 s=w   Y  d}q|S )aZ  Performs an update on a component while using a progress bar.

    Args:
      components: [schemas.Component], The components that are going to be acted
        on.
      action: str, The action that is printed for this update.
      action_func: func, The function to call to actually do the update.  It
        takes a single argument which is the component id.
      first: bool, True if this is the first stacked ProgressBar group.
      last: bool, True if this is the last stacked ProgressBar group.

    Returns:
      dict, Map of component ID to result of action_func for each component.
    z{action}: {name})rC  r?  r!   )labelr   firstlastprogress_callbackNF)	enumerater   rc   rd   r   ProgressBarr	   r-  r,   r<   SetProgress)rW   r1   rC  action_funcrK  rL  results_mapindexr?   rJ  pbresultr)   r)   r*   _UpdateWithProgressBarv  s   z$UpdateManager._UpdateWithProgressBarc                    s    fdd}|S )Nc                    s   j  j| |ddS )Ncomponents.update)rN  r   )Downloadr  r  rN  r   r   r)   r*   Inner  s   z.UpdateManager._DownloadFunction.<locals>.Innerr)   )rW   r   r   r\  r)   r[  r*   _DownloadFunction  s   zUpdateManager._DownloadFunctionc                    s    fdd}|S )Nc                    s   j  j| |  |dS )NrM  )Installr  rZ  r   downloads_mapr   r)   r*   r\    s   z-UpdateManager._InstallFunction.<locals>.Innerr)   )rW   r   r   r`  r\  r)   r_  r*   _InstallFunction  s   zUpdateManager._InstallFunctionc                 C   sB   |st dtjj}tjjj rt	
d d}| j||||dS )a  Installs the given components at the version you are current on.

    Args:
      components: [str], A list of component ids to install.
      throw_if_unattended: bool, True to throw an exception on prompts when
        not running in interactive mode.
      restart_args: list of str or None. If given, this gcloud command should be
        run in event of a restart (ex. if we're using a bundled Python
        installation to do this update).

    Raises:
      InvalidComponentError: If any of the given component ids do not exist.

    Returns:
      bool, True if the update succeeded (or there was nothing to do, False if
      if was cancelled by the user.
    z&You must specify components to installz_Additional component repositories are currently active.  Running `update` instead of `install`.N)throw_if_unattendedr   restart_args)rN   r   r   r   r   rp   rq   rr   rs   r	   r   Update)rW   r1   rb  rc  r   r)   r)   r*   r^    s   
zUpdateManager.Installc              
   C   s`  |  t}|r| j|dd n| jdd z| j|dd\}}W n tjy8 } z| |W  Y d}~S d}~ww |}	|rE| |||}nt|j	j
 }||}
||}| || | tj |
s|s| tjd t }|j|jt| d	d
 W d   n1 sw   Y  |  d	S t| j |  rt|
rt  tt  | j!|d |	rd}nd}| j"||d\}}| j#d	t|
d | $t%|&|
| d | $t%|'|
|@ d | $t%|'||
 d | tj t()|jj*j+tj,j-|jj- t.j/t0|dsdS |'|}|&|
}|D ]}t12|j3|j-j4 qt5j6tjd9 | tjd | j7|d| 8||d	dd}| j7|d|j9| | d | j7|d| :|||dd	d W d   n	1 slw   Y  |  |;  t }|j<|j| j=d}|j|jt| d	d
 W d   n	1 sw   Y  | j>|jd z
t?@ }|A  W n tBy } ztd| W Y d}~nd}~ww tCD  |  t}||kr| tjt.Ed | tjd |	s| jtjd jF|d!dd" | jGr.tHItJjKd#s.| L }|rtd$Fd%M| | N }|r.td&Fd'M| d	S )(a4  Performs an update of the given components.

    If no components are provided, it will attempt to update everything you have
    installed.

    Args:
      update_seed: list of str, A list of component ids to update.
      throw_if_unattended: bool, True to throw an exception on prompts when
        not running in interactive mode.
      version: str, The SDK version to update to instead of latest.
      restart_args: list of str or None. If given, this gcloud command should be
        run in event of a restart (ex. if we're using a bundled Python
        installation to do this update).

    Returns:
      bool, True if the update succeeded (or there was nothing to do, False if
      if was cancelled by the user.

    Raises:
      InvalidComponentError: If any of the given component ids do not exist.
    updater1   r~   r   )r~   rX  r   NzAll components are up to date.Tr   )argsz$Installing components from version: z!You will be upgraded to version: r0  r   r   removedupdated	installed)messagerb  Fr   Performing in place update...
DownloadingrK  rL  Uninstalling
Installingr   )snapshotz)Failed to update universe descriptors: %sz1Start a new shell for the changes to take effect.z
Update done!
zvTo revert your CLI to the previously installed version, you may run:
  $ gcloud components update --version {current}
)currentr   CLOUDSDK_REINSTALL_COMPONENTSz  There are other instances of Google Cloud tools on your system PATH.
  Please remove the following to avoid confusion or accidental invocation:

  {0}

  r   z  There are alternate versions of the following Google Cloud tools on
  your system PATH. Please double check your PATH:

  {0}

  z
  )OrA  _SHELL_RCFILESr   r   r   r  r2  _HandleInvalidUpdateSeedsr-   rt  r1   keysToRemove	ToInstall_HandleBadComponentInstallStater,  r	   r-  r   r   r  r  r  r  ClearDeprecatedDirsr   EnsureSDKWriteAccessr   IsPythonBundledr2   r+   r   BUNDLED_PYTHON_REMOVAL_WARNING_RestartIfUsingBundledPythonr3  r   rI  rl   DetailsForCurrentDetailsForLatestr   PrintReleaseNotesDiffsdk_definitionrelease_notes_urlr   r   r   PromptContinue_DONT_CANCEL_MESSAGEr
   Installsr<   version_stringr   UninterruptibleSectionrW  r]  	Uninstallra  ClearBackupr   r   _PostProcessr   UniverseDescriptorUpdateAllDescriptors	Exceptionr   PromptAndInstallPythonOnMacFormatRequiredUserActionr   r   r   GetEncodedValuer   environFindAllOtherToolsOnPathr   FindAllDuplicateToolsOnPath)rW   update_seedrb  r   rc  sha256dict1r   r   r7  original_update_seed	to_remove
to_installr   r1  r   r  components_to_installcomponents_to_removerf   r`  new_diffuniverse_descriptor_datasha256dict2bad_commandsduplicate_commandsr)   r)   r*   rd    s&  











zUpdateManager.Updatec                 C   sD   |   rdt||B v rtj| jd s |d dS dS dS dS )zDeal with bad install state of kubectl component on darwin-arm machines.

    Args:
      update_seed: list of str, A list of component ids to update.
      to_install: set of str, A set of component ids to install.

    kubectlz/bin/kubectlzkubectl-darwin-armN)r   r.   r   r   r   r   add)rW   r  r  r)   r)   r*   r|    s
   z-UpdateManager._HandleBadComponentInstallStatec                 C   s   | |}|s	|S ttjdrt|| S tt}||@ }|D ]}td| t	|}|r4t| q ||8 }|rv|}	t }
|rS| j
dd\}}| |}	||	 }
g }|	rb|dd|	 |
ro|dd|
 td|t|| S )	a  Checks that the update seeds are valid components.

    Args:
      diff: The ComponentSnapshotDiff.
      version: str, The SDK version if in install mode or None if in update
        mode.
      update_seed: [str], A list of component ids to update.

    Raises:
      InvalidComponentError: If any of the given component ids do not exist.

    Returns:
      [str], The update seeds that should be used for the install/update.
    rv  z Component [%s] no longer exists.rX  r
  z*The following components are unknown [{}].r   zThe following components are not available for your current CLI version [{}]. Please run `gcloud components update` to update your Google Cloud CLI.r   )InvalidUpdateSeedsr   r  r   r  r.   _IGNORED_MISSING_COMPONENTSr	   r   r   r   appendr   r   rN   )rW   r   r   r  invalid_seedsignored
deprecateditemadditional_msgcompletely_invalid_seedsupdate_required_seedsr  latest_diffmsgsr)   r)   r*   rx    sD   




z'UpdateManager._HandleInvalidUpdateSeedsc           
         s   t jt jjtj t j st S  fddt 	 D }t }t }|D ]<}t
j||d}|rft j |}	|rQ|tfdd|D t|	g  |rf|tfdd|D t|	g  q*||S )zBHelper function to find commands matching SDK bin dir on the path.c                    s0   g | ]}t jt j |r|d s|qS ).)r   r   r   r   
startswithr3   f)bin_dirr)   r*   r7     s
    
z2UpdateManager._FindToolsOnPath.<locals>.<listcomp>r   c                 3   s.    | ]} j tj|vrtj|V  qd S r_   r   r   r   r   r  rV   r)   r*   r$        
z1UpdateManager._FindToolsOnPath.<locals>.<genexpr>c                 3   s.    | ]} j tj|v rtj|V  qd S r_   r  r  rV   r)   r*   r$    r  )r   r   r   r   r   rm   BIN_DIR_NAMEr8  r.   listdirr   SearchForExecutableOnPathre  union)
rW   r   
duplicatesothercommandsduplicates_in_sdk_rootr  r~   existing_paths	this_toolr)   )r  rW   r*   _FindToolsOnPath  s4   
zUpdateManager._FindToolsOnPathc                 C      | j |dddS )zSearches the PATH for any other instances of Cloud SDK tools.

    Args:
      path: str, A path to use instead of the PATH environment variable.

    Returns:
      {str}, The other executable paths that are not in the SDK root directory.
    FTr   r  r  r  rW   r   r)   r)   r*   r    s   	z%UpdateManager.FindAllOtherToolsOnPathc                 C   r  )a  Searches PATH for alternate versions of Cloud SDK tools in installation.

    Some gcloud components include duplicate versions of commands, so if
    those component locations are on a user's PATH then multiple versions of
    the commands may be found.

    Args:
      path: str, A path to use instead of the PATH environment variable.

    Returns:
      {str}, Alternate executable paths that are in the SDK root directory.
    TFr  r  r  r)   r)   r*   r    s   z)UpdateManager.FindAllDuplicateToolsOnPathc           	         s  | j |dd |sdS |  }| }t|}|t|j  }|r-tdjd|d|j	|| j
d |  rC |j	|| jdO  t fdd	t|jD }|r_td
jd|d sj| tjd dS | jddd t| dd d}t|}| |d | tj t| j |  rt rt  tt |   t !t"sdS t#j$tjd | tjd | j%|d|j&ddd W d   n1 sw   Y  | '  | tjd dS )zUninstalls the given components.

    Args:
      ids: list of str, The component ids to uninstall.

    Raises:
      InvalidComponentError: If any of the given component ids are not
        installed or cannot be removed.
    removerf  NzCThe following components are not currently installed [{components}]r   r0   r   c                 3   s&    | ]\}}| v r|j r|V  qd S r_   )is_required)r3   c_idr?   r  r)   r*   r$    s    z'UpdateManager.Remove.<locals>.<genexpr>zxThe following required components are included in or depend on the given components and cannot be removed [{components}]zNo components to remove.
Trh  c                 S   ra   r_   rb   re   r)   r)   r*   rg   -  rh   z&UpdateManager.Remove.<locals>.<lambda>ri   ri  rm  rn  rq  rp  z
Uninstall done!
)(r   r   r(  r.   r1   ry  rN   r   r   ConsumerClosureForComponentsr   r   r*  r   r  r,  r	   r-  r   rk   ComponentsFromIdsrl   rI  r   r~  r   r  r2   r+   r   r  r  r   r  r  r   r  rW  r  r  )	rW   idsr   rs  id_setnot_installedrequired_components_removedr  components_to_displayr)   r  r*   Remove  sr   






zUpdateManager.Removec                 C   s   |    |  }| std| jddd t| j t|	 
 }|  r0|s0tt |   tjdds<dS | tjd |  |   | tjd dS )	zRestores the latest backup installation of the Cloud SDK.

    Raises:
      NoBackupError: If there is no valid backup to restore.
    z(There is currently no backup to restore.Frh  zJYour Google Cloud CLI installation will be restored to its previous state.rl  NzRestoring backup...zRestoration done!
)r   r   	HasBackuprP   r   r   r~  r   r2   BackupInstallationStater   r  r	   r   r  r  r   r  r,  r-  RestoreBackupr  )rW   r   backup_has_bundled_pythonr)   r)   r*   RestoreI  s*   

zUpdateManager.Restorec                 C   s(   | j dd}|jj}| |j|j|jS )zDo a reinstall of what we have based on a fresh download of the SDK.

    Returns:
      bool, True if the update succeeded, False if it was cancelled.
    zcomponents.reinstallr
  )r   r  schema_version_DoFreshInstallrl  	no_updater   )rW   rs  r  r)   r)   r*   	Reinstallk  s   zUpdateManager.Reinstallc                 C   s   |  |jj|jj|jjS )a&  Do a reinstall of what we have based on a fresh download of the SDK.

    Args:
      e: snapshots.IncompatibleSchemaVersionError, The exception we got with
        information about the new schema version.

    Returns:
      bool, True if the update succeeded, False if it was cancelled.
    )r  r  rl  r  r   )rW   r7  r)   r)   r*   r2  w  s   

zUpdateManager._ReinstallOnErrorc                 C   s  |    ttjdr|   |r| jtj|dd |rdS t	
| j |   tjdd}|s2dS | jddd |  }z"tjdtjd	}|j||jd
}W d   n1 sYw   Y  W n tjyy   td tjddd |   Y nw t|  }tttj}	t|	dd| tj|j ddd}
t!j"t#j$d|
g|	d}|% }|r|   tjdtjd	}|&||j W d   n1 sw   Y  | tjd dS )a  Do a reinstall of what we have based on a fresh download of the SDK.

    Args:
      message: str, A message to show to the user before the re-installation.
      no_update: bool, True to show the message and tell the user they must
        re-download manually.
      download_url: The URL the Cloud SDK can be downloaded from.

    Returns:
      bool, True if the update succeeded, False if it was cancelled.
    rv  T)r}   r   Fz
The component manager must perform a self update before you can continue.  It and all components will be updated to their latest versions.r  rh  z-Downloading and extracting updated components)rJ  r   rM  Nz.An updated Google Cloud CLI failed to downloadzHandling re-installation errorexc_inforo   rn   bootstrappingz
install.pyz-S)envz/Creating backup and activating new installationz
Components updated!
)'r   r   r  r   r  _RaiseReinstallationFailedErrorr,  r	   r-  r   r~  r   r  r   r  r   r   rP  CreateStagingFromDownloadrQ  r   rE   r%   r   rk   r   ry  	EncodeEnvdictSetEncodedValuer   r   r   
subprocessPopenr&   
executablewaitReplaceWith)rW   rl  r  download_urlanswerr   rU  staging_stateinstalled_component_idsr  installer_pathpret_valr)   r)   r*   r    sj   

zUpdateManager._DoFreshInstallc                 C   s   t djtjjd)NzbAn error occurred while reinstalling the Google Cloud CLI.  Please download a new copy from: {url})r   )rQ   r   r   r   r   rV   r)   r)   r*   r    s   z-UpdateManager._RaiseReinstallationFailedErrorc                 C   s   |   }t|t|  }|sdS d|}|sdj|d}| jtj|dd zddgt| }| j	|d|dsEt
d	j|d
|dW n tyd   | tjdd
dgt dd    w t| dS )rw   Tr   zCThis action requires the installation of components: [{components}]r0   ru  r1   install)rb  rc  zThe following components are required to run this command, but are not
currently installed:
  [{components_list}]

To install them, re-run the command and choose 'yes' at the installation
prompt, or run:
  $ gcloud components install {components}

r   )components_listr1   zjInstalling component in a new window.

Please re-run this command when installation is complete.
    $ {0}gcloudr!   N)r   r.   r   r   r   r,  r	   r-  r-   r^  rR   
SystemExitr   GetDecodedArgvRestartCommand)rW   r1   r}   r~   r  missing_componentsmissing_components_list_strrc  r)   r)   r*   r|     s@   

	

z(UpdateManager._EnsureInstalledAndRestartc                 C   s
   t | jS r_   )_IsPythonBundledr   rV   r)   r)   r*   r    s   
zUpdateManager.IsPythonBundledc                 C   s   t | j|| d S r_   )RestartIfUsingBundledPythonr   )rW   rg  r~   r)   r)   r*   r       z*UpdateManager._RestartIfUsingBundledPythonc                 C   sH   t  j}|std}|rtdj|d |S tdt	j
|dS )z)Determines the path to the gcloud binary.r  zUsing gcloud found at [{path}]r  zJA path to `gcloud` could not be found. Please check your SDK installation.)r   r   sdk_bin_pathr   FindExecutableOnPathr	   r   r   rO   r   r   r   )rW   r  gcloud_pathr)   r)   r*   _GetGcloudPath  s   

zUpdateManager._GetGcloudPathc                 C   sB  d}|r|j jr|j jd}|pddg}| jr|d |  }tj tjj	kr6t
j|d g|R  }n	t
j|g|R  }| tj zLtjddd	: zt
j|d
tjjtjjd}W n tt
jt
jfys   tjdd
d t w |r~td t W d   W dS 1 sw   Y  W dS  ty   td Y dS w )a  Runs the gcloud command to post process the update.

    This runs gcloud as a subprocess so that the new version of gcloud (the one
    we just updated to) is run instead of the old code (which is running here).
    We do this so the new code can say how to correctly post process itself.

    Args:
      snapshot: ComponentSnapshot, The component snapshot for the version
        we are updating do. The location of gcloud and the command to run can
        change from version to version, which is why we try to pull this
        information from the latest snapshot.  For a restore operation, we don't
        have that information so we fall back to a best effort default.
    Nr   r1   zpost-processz--no-compile-pythonz.cmdz Performing post processing stepsg      ?)rl  
tick_delayT)no_exitout_funcerr_funcz)Failed to execute post-processing commandr  z'Post-processing command exited non-zerozKPost processing failed.  Run `gcloud info --show-log` to view the failures.)r  post_processing_commandrt   r   r  r  r   r"   r#   WINDOWSr   ArgsForCMDToolArgsForExecutableToolr,  r	   r-  r   ProgressTrackerExecfile_only_loggerr   r   InvalidCommandErrorPermissionErrorr]   r   )rW   rs  r~   r  gcloud_argsr  r)   r)   r*   r  (  sR   




&
zUpdateManager._PostProcessNN)F)NNNNF)r   F)TFr_   )Nr   )FF)FN)NFNN)NTT);rG   rH   rI   rJ   r  r   r   r{   r"   r$   r   x86_64r*  staticmethodrv   r   r   r   rU   r   r   r,  r   r   r   r   r   r   r   r   r	  r   r"  r  r  r3  rA  rI  rW  r]  ra  r^  rd  r|  rx  r  r  r  r  r  r  r2  r  r  r|   r  r  r  r  r)   r)   r)   r*   rm      s    



E

+

Z-

:






!
 @
:
 
H"K
>
rm   c                  C   sF   t  } tj| jd}ttjtj	| tj|tj
tj	S )zCCopy the current Python to temporary directory and return its path.python)r   TemporaryDirectoryr   r   r   shutilcopytreer   r&   r  basename)temp_dirtemp_python_install_dirr)   r)   r*   
CopyPython]  s   r  c                 C   s   t | tjS r_   )r   r   r&   r  )r   r)   r)   r*   r  g  s   r  c                 C   s   t j }|t jju r@t| rBt s0tj	tj
t jpdd}td| td t||t dd td d S d S d S )Nr   z
gcloud.cmda  Cannot use bundled Python installation to update Google Cloud CLI in
non-interactive mode. Please run again in interactive mode.



If you really want to run in non-interactive mode, please run the
following command before re-running this one:



  FOR /F "delims=" %i in ( '""{0}"" components copy-bundled-python'
  ) DO (
    SET CLOUDSDK_PYTHON=%i
  )

(Substitute `%%i` for `%i` if in a .bat script.)r!   F)rg  r~   r  blockr   )r   r"   r#   r  r  r   	CanPromptr   r   r   r   r   r   r  r	   r%   r   r&   r'   r  r  )r   rg  r~   r(   gcloud_cmd_pathr)   r)   r*   r  k  s"   


r  Tc           
      C   s   | pt  } |pt dd }tj| g|R d|i}dd |D }tj| }|dkr/d}d	d	d |D }t
jd
j||d t
d| | t
j  t
j  |r^t| dS tj }i }t r| }|jtjju rdd }	dd	t|	|}tj|fddi| dS )aS  Calls command again with the same arguments as this invocation and exit.

  Args:
    command: str, the command to run (full path to Python file). If not
      specified, defaults to current `gcloud` installation.
    args: list of str or None. If given, use these arguments to the command
      instead of the args for this process.
    python: str or None, the path to the Python interpreter to use for the new
      command invocation (if None, uses the current Python interpreter)
    block: bool, whether to wait for the restarted command invocation to
      terminate before continuing.
  r!   Nr  c                 S      g | ]}t |qS r)   )r   Encoder3   ar)   r)   r*   r7     r  z"RestartCommand.<locals>.<listcomp>z	gcloud.pyr  r   c                 S   r  r)   )r   SafeTextr!  r)   r)   r*   r7     s    
z)Restarting command:
  $ {command} {args}
)r~   rg  zRestarting command: %s %sc                 S   s   dt |  d S )N")r   r   )sr)   r)   r*   Quote  r  zRestartCommand.<locals>.Quotezcmd.exe /c "{0} & pause"shellT)r   
GcloudPathr   r  r   ArgsForPythonToolr   r   r  r   r	   r-  rG  r   r   rF  r   errr  r   r{   r#   r   r  AsyncPopenArgsr   r"   r  r   r  r  )
r~   rg  r  r  command_argsshort_commandlog_argscurrent_platform
popen_argsr&  r)   r)   r*   r    s<   




r  r  )NNNT)GrJ   
__future__r   r   r   r9  r   r  r  r&   r   googlecloudsdk.corer   r   r   r   r	   r
   r   r   googlecloudsdk.core.consoler   r   r   googlecloudsdk.core.resourcer   'googlecloudsdk.core.universe_descriptorr   googlecloudsdk.core.updaterr   r   r   r   r   r   googlecloudsdk.core.utilr   r   r   r   r   	six.movesr   _GAE_REDIRECT_MSGr  rw  r/   r  r  r+   r2   rC   rE   rL   rM   rN   rO   rP   rQ   rR   rS   r[   r]   r^   rl   objectrm   r  r  r  r  r)   r)   r)   r*   <module>   s   	


"
          

%