o
    o                     @   sB  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	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ZG dd dejZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZdS )a3  Classes for working with component snapshots.

A snapshot is basically a state of the world at a given point in time.  It
describes the components that exist and how they depend on each other.  This
module lets you do operations on snapshots like getting dependency closures,
as well as diff'ing snapshots.
    )absolute_import)division)unicode_literalsN)config)
exceptions)log)
installers)schemas)files)	platformsc                   @   s   e Zd ZdZdS )Errorz(Base exception for the snapshots module.N)__name__
__module____qualname____doc__ r   r   B/tmp/google-cloud-sdk/lib/googlecloudsdk/core/updater/snapshots.pyr   -   s    r   c                       s"   e Zd ZdZd fdd	Z  ZS )URLFetchErrorz%Error for problems fetching via HTTP.NFc                    sT   d}|r|d |7 }n|r|d7 }n|d7 }|r |d |7 }tt| | d S )Nz.Failed to fetch component listing from server.z Received response code [{0}].z" The repository URL was malformed.z+ Check your network settings and try again.z
Please ensure that the additional component repository [{0}] is correct and still valid.  To remove it, run:
  $ gcloud components repositories remove {0})formatsuperr   __init__)selfcode	malformed
extra_repomsg	__class__r   r   r   5   s   
zURLFetchError.__init__)NFNr   r   r   r   r   __classcell__r   r   r   r   r   2   s    r   c                           e Zd ZdZ fddZ  ZS )MalformedSnapshotErrorz(Error with the contents of the snapshot.c                    s   t t| d d S )Nz0Failed to process component listing from server.)r   r!   r   r   r   r   r   r   I   s   
zMalformedSnapshotError.__init__r   r   r   r   r   r!   F       r!   c                       r    )IncompatibleSchemaVersionErrorzFError for when we are unable to parse the new version of the snapshot.c                    s   t t| d || _d S )NzCThe latest version snapshot is incompatible with this installation.)r   r$   r   schema_version)r   r%   r   r   r   r   Q   s   

z'IncompatibleSchemaVersionError.__init__r   r   r   r   r   r$   N   r#   r$   c                   @   s   e Zd ZdZedZedd Zedd Z	edd Z
ed-d
dZedd Zedd Zdd Zdd Zdd Zdd Zdd Zd.ddZd.ddZd.dd Zd!d" Zd.d#d$Zd.d%d&Zd.d'd(Zd.d)d*Zd.d+d,ZdS )/ComponentSnapshota[  Contains a state-of-the-world for existing components.

  A snapshot can be loaded from different sources.  It can be the latest that
  exists on the server or it can be constructed from local install state.
  Either way, it describes the components that are available, how they depend
  on each other, and other information about them like descriptions and version
  information.

  Attributes:
    revision: int, The global revision number for this snapshot.  If it was
      created from an InstallState, this will be -1 to indicate that it is
      potentially a composition of more than one snapshot.
    sdk_definition: schemas.SDKDefinition, The full definition for this
      component snapshot.
    url: str, The full URL of the file from which this snapshot was loaded.
      This could be a web address like http://internet.com/components.json or
      a local file path as a URL like file:///some/local/path/components.json.
      It may also be None if the data did not come from a file.
    components = dict from component id string to schemas.Component, All the
      Components in this snapshot.
  z^\w+://c                 C   s$   t j|r|S tj| d | S )a  Convert the potentially relative value into an absolute URL.

    Args:
      url: str, The URL of the component snapshot this value was found in.
      value: str, The value of the field to make absolute.  If it is already an
        absolute URL, it is returned as-is.  If it is relative, it's path
        is assumed to be relative to the component snapshot URL.

    Returns:
      str, The absolute URL.
    /)r&   ABSOLUTE_REsearchospathdirname)urlvaluer   r   r   _GetAbsoluteURLo   s   z!ComponentSnapshot._GetAbsoluteURLc                 C   sd   t | }t|}W d   n1 sw   Y  d| ds"dnd | dd }t||fS )zLoads a snapshot from a local file.

    Args:
      snapshot_file: str, The path of the file to load.

    Returns:
      A ComponentSnapshot object
    Nzfile://r'    \)r
   
FileReaderjsonload
startswithreplacer&   _FromDictionary)snapshot_filefdatar-   r   r   r   FromFile   s   

zComponentSnapshot.FromFilec                     sd   t jj}t|tdg }|rtd|| |dd | d  fdd| D }t j| S )a  Loads a snapshot from a series of URLs.

    Args:
      *urls: str, The URLs to the files to load.
      **kwargs: command_path: the command path to include in the User-Agent
        header if the URL is HTTP

    Returns:
      A ComponentSnapshot object.

    Raises:
      URLFetchError: If the URL cannot be fetched.
      TypeError: If an unexpected keyword argument is given.
    command_pathz,{0} got an unexpected keyword argument '{1}'unknownr   c                    s$   g | ]}t j| |kd |fqS ))is_extra_repo)r&   _DictFromURL).0r-   r<   firstr   r   
<listcomp>   s    
z.ComponentSnapshot.FromURLs.<locals>.<listcomp>)	r&   FromURLsr   set	TypeErrorr   popgetr7   )urlskwargscurrent_function_nameunexpected_argsr:   r   rA   r   rD      s   
zComponentSnapshot.FromURLsFc              
   C   s   |r| nd}zt | |}W n tjjy&   tjdj| ddd d}Y nw |du r0t|d|j	}|tj
jkr?t||dzt|jd}|W S  tyc } ztd	| | t d}~ww )
a{  Loads a json dictionary from a URL.

    Args:
      url: str, The URL to the file to load.
      command_path: the command path to include in the User-Agent header if the
        URL is HTTP
      is_extra_repo: bool, True if this is not the primary repository.

    Returns:
      A ComponentSnapshot object.

    Raises:
      URLFetchError: If the URL cannot be fetched.
    NzCould not fetch [{url}])r-   T)exc_info)r   )r   r   zutf-8z!Failed to parse snapshot [{}]: {})r   MakeRequestrequestsr   	HTTPErrorr   debugr   r   status_codecodesokr3   loadscontentdecode
ValueErrorr!   )r-   r<   r>   r   responser   r:   er   r   r   r?      s(   
zComponentSnapshot._DictFromURLc              
   C   s<   |   }dd | D }tjdddddd|i d}t|S )ax  Loads a snapshot from the local installation state.

    This creates a snapshot that may not have actually existed at any point in
    time.  It does, however, exactly reflect the current state of your local
    SDK.

    Args:
      install_state: install_state.InstallState, The InstallState object to load
        from.

    Returns:
      A ComponentSnapshot object.
    c                 S   s   g | ]}|  qS r   )ComponentDefinition)r@   manifestr   r   r   rC      s    z6ComponentSnapshot.FromInstallState.<locals>.<listcomp>N)revisionr%   release_notes_urlversiongcloud_rel_pathpost_processing_command
componentsnotifications)InstalledComponentsvaluesr	   SDKDefinitionr&   )install_state	installedrc   sdk_definitionr   r   r   FromInstallState   s   z"ComponentSnapshot.FromInstallStatec                  G   s   d}| D ]e\}}t j|}|r|jrt||j|_|jtjj	kr&t
|t j|}|r_|jjr<t||jj|j_|jrGt||j|_|jD ]}|jrS|jjsTqJt||jj|j_qJ|sd|}q|| qt|S )aA  Loads a snapshot from a dictionary representing the raw JSON data.

    Args:
      *data: ({}, str), A tuple of parsed JSON data and the URL it came from.

    Returns:
      A ComponentSnapshot object.

    Raises:
      IncompatibleSchemaVersionError: If the latest snapshot cannot be parsed
        by this code.
    N)r	   rg   SchemaVersionr-   r&   r/   r`   r   INSTALLATION_CONFIGsnapshot_schema_versionr$   FromDictionaryr%   r_   rc   r:   sourceMerge)r:   mergedjson_dictionaryr-   r%   sdk_defcr   r   r   r7      s:   

z!ComponentSnapshot._FromDictionaryc                    s   || _ |j| _|j| _tdd |jD | _tdd |jD  i | _t D ]\}}t fdd|D | j|< q(tdd | jD | _	t| jD ]\}}|D ]
}| j	| 
| qRqLd S )Nc                 s   s    | ]}|j |fV  qd S Nidr@   ru   r   r   r   	<genexpr>&      z-ComponentSnapshot.__init__.<locals>.<genexpr>c                 s   s     | ]}|j t|jfV  qd S rv   )rx   rE   dependenciesry   r   r   r   rz   '  s    c                 3   s    | ]	}| v r|V  qd S rv   r   )r@   dep_iddepsr   r   rz   +  s    c                 s   s    | ]}|t  fV  qd S rv   rE   )r@   rx   r   r   r   rz   .  r{   )rj   r^   r`   dictrc    _ComponentSnapshot__dependenciessix	iteritemsrE   _ComponentSnapshot__consumersadd)r   rj   compdep_idscomponent_idr}   r   r~   r   r   "  s   zComponentSnapshot.__init__c                 C   s`   t  }t|}|r.| }|| jvs||v rq|| j| s q|| |||  |s
|S )a~  Calculates a connected closure for the components with the given ids.

    Performs a breadth first search starting with the given component ids, and
    returns the set of components reachable via the given adjacency map.

    Args:
      ids: [str], The component ids to get the closure for.
      adjacencies: {str: set}, Map of component ids to the set of their
        adjacent component ids.
      component_filter: schemas.Component -> bool, A function applied to
        components that determines whether or not to include them in the
        closure.

    Returns:
      set of str, The set of component ids in the closure.
    )rE   collectionsdequepopleftrc   r   extend)r   idsadjacenciescomponent_filterclosure
to_processcurrentr   r   r   _ClosureFor3  s   

zComponentSnapshot._ClosureForc                 C   s   | j |S )zGets the schemas.Component from this snapshot with the given id.

    Args:
      component_id: str, The id component to get.

    Returns:
      The corresponding schemas.Component object.
    rc   rH   )r   r   r   r   r   ComponentFromIdP  s   	z!ComponentSnapshot.ComponentFromIdc                    s   t  fdd|D S )zGets the schemas.Component objects for each of the given ids.

    Args:
      component_ids: iterable of str, The ids of the  components to get

    Returns:
      The corresponding schemas.Component objects.
    c                 3   s    | ]	} j |V  qd S rv   r   r@   r   r"   r   r   rz   d  s    z6ComponentSnapshot.ComponentsFromIds.<locals>.<genexpr>r   r   component_idsr   r"   r   ComponentsFromIds[  s   	z#ComponentSnapshot.ComponentsFromIdsc                    s   t  fddt| jD S )zGets all components in the snapshot that match the given platform.

    Args:
      platform_filter: platforms.Platform, A platform the components must match.

    Returns:
      set(str), The matching component ids.
    c                 3   s$    | ]\}}|j  r|V  qd S rv   platformMatches)r@   c_id	componentplatform_filterr   r   rz   p  s   
 
z<ComponentSnapshot.AllComponentIdsMatching.<locals>.<genexpr>)rE   r   r   rc   )r   r   r   r   r   AllComponentIdsMatchingg  s   	z)ComponentSnapshot.AllComponentIdsMatchingNc                        fdd}|  || j|S )a  Gets all the components that are depended on by any of the given ids.

    Args:
      component_ids: list of str, The ids of the components to get the
        dependencies of.
      platform_filter: platforms.Platform, A platform that components must
        match to be pulled into the dependency closure.

    Returns:
      set of str, All component ids that are in the dependency closure,
      including the given components.
    c                       | j  S rv   r   ru   r   r   r   <lambda>      zBComponentSnapshot.DependencyClosureForComponents.<locals>.<lambda>)r   r   r   r   r   r   r   r   r   DependencyClosureForComponentss  s   z0ComponentSnapshot.DependencyClosureForComponentsc                    r   )a  Gets all the components that depend on any of the given ids.

    Args:
      component_ids: list of str, The ids of the components to get the consumers
        of.
      platform_filter: platforms.Platform, A platform that components must
        match to be pulled into the consumer closure.

    Returns:
      set of str, All component ids that are in the consumer closure, including
      the given components.
    c                    r   rv   r   r   r   r   r   r     r   z@ComponentSnapshot.ConsumerClosureForComponents.<locals>.<lambda>)r   r   r   r   r   r   ConsumerClosureForComponents  s   z.ComponentSnapshot.ConsumerClosureForComponentsc                    s.   fddj D } fdd}|||S )aK  Gets all the components that are connected to any of the given ids.

    Connected means in the connected graph of dependencies.  This is basically
    the union of the dependency and consumer closure for the given ids.

    Args:
      component_ids: list of str, The ids of the components to get the
        connected graph of.
      platform_filter: platforms.Platform, A platform that components must
        match to be pulled into the connected graph.

    Returns:
      set of str, All component ids that are connected to the given ids,
      including the given components.
    c                    s"   i | ]}| j |  j| B qS r   )r   r   r@   r   r"   r   r   
<dictcomp>  s    z9ComponentSnapshot.ConnectedComponents.<locals>.<dictcomp>c                    r   rv   r   r   r   r   r   r     r   z7ComponentSnapshot.ConnectedComponents.<locals>.<lambda>)rc   r   )r   r   r   r   r   r   r   r   r   ConnectedComponents  s
   
z%ComponentSnapshot.ConnectedComponentsc                 C   s4   dd }|  |g| j|}|  |g| j|}||@ S )a  Gets the components strongly connected to the given component id.

    In other words, this functions returns the strongly connected "component" of
    the dependency graph for the given component id. In this context the
    strongly connected "component" is the set of ids whose components are both
    dependencies and consumers of the given component. In practice this can be
    used to determine the platform-specific subcomponent ID's for a given
    component ID, since they will always be mutually dependent.

    Args:
      component_id: str, The id of the component for which to get the strongly
        connected components.

    Returns:
      set of str, The ids of the components that are strongly connected to the
        component with the given id.
    c                 S   s   dS )NTr   r   r   r   r   r     s    z?ComponentSnapshot.StronglyConnectedComponents.<locals>.<lambda>)r   r   r   )r   r   r   dependency_closureconsumer_closurer   r   r   StronglyConnectedComponents  s   

z-ComponentSnapshot.StronglyConnectedComponentsc                    st   d} |}|r8|j r8|jr|jjS fddj| D } fdd|D }|D ]
}||jjp5d7 }q-|S )a  Computes the effective size of the given component.

    If the component does not exist or does not exist on this platform, the size
    is 0.

    If it has data, just use the reported size of its data.

    If there is no data, report the total size of all its direct hidden
    dependencies (that are valid on this platform).  We don't include visible
    dependencies because they will show up in the list with their own size.

    This is a best effort estimation.  It is not easily possible to accurately
    report size in all situations because complex dependency graphs (between
    hidden and visible components, as well as circular dependencies) makes it
    infeasible to correctly show size when only displaying visible components.
    The goal is mainly to not show some components as having no size at all
    when they are wrappers around platform specific components.

    Args:
      component_id: str, The component to get the size for.
      platform_filter: platforms.Platform, A platform that components must
        match in order to be considered for any operations.

    Returns:
      int, The effective size of the component.
    r   c                    s   g | ]}  |qS r   )r   r@   dr"   r   r   rC     s    z?ComponentSnapshot.GetEffectiveComponentSize.<locals>.<listcomp>c                    s(   g | ]}|j  r|jr|jr|qS r   )r   r   	is_hiddenr:   r   r   r   r   rC     s    

)r   r   r   r:   sizer   )r   r   r   r   r   r   r   r   r   r   GetEffectiveComponentSize  s   

z+ComponentSnapshot.GetEffectiveComponentSizec                 C   s   t | ||dS )a  Creates a ComponentSnapshotDiff based on this snapshot and the given one.

    Args:
      latest_snapshot: ComponentSnapshot, The latest state of the world that we
        want to compare to.
      platform_filter: platforms.Platform, A platform that components must
        match in order to be considered for any operations.

    Returns:
      A ComponentSnapshotDiff object.
    r   )ComponentSnapshotDiff)r   latest_snapshotr   r   r   r   
CreateDiff  s   zComponentSnapshot.CreateDiffc                    s"     } fdd|D }|S )Nc                    s   g | ]	}t | d qS r   )ComponentInfor   r   r   r   rC   
  s    z:ComponentSnapshot.CreateComponentInfos.<locals>.<listcomp>)r   )r   r   all_componentsinfosr   r   r   CreateComponentInfos  s
   
z&ComponentSnapshot.CreateComponentInfosc              	      s   | j  } r` fdd|d D }|s&td ddd |d D d|d v rLt|d d  D ]}|d	vrC|d d |= q6d
|d d d< ||d< t| D ]	}|dvr_||= qVt|t	j
|dddd dS )a  Writes this snapshot back out to a JSON file.

    Args:
      path: str, The path of the file to write to.
      component_id: Limit snapshot to this component.
          If not specified all components are written out.

    Raises:
      ValueError: for non existent component_id.
    c                    s   g | ]
}|d   kr|qS rw   r   ry   r   r   r   rC     s    z1ComponentSnapshot.WriteToFile.<locals>.<listcomp>rc   z'Component {} is not in this snapshot {},c                 S   s   g | ]}|d  qS rw   r   ry   r   r   r   rC   !  s    r:   r   )contents_checksumtyperp   r0   rp   )rc   r%   r^   r`      T)r   z: )indent	sort_keys
separatorsN)rj   ToDictionaryrX   r   joinlistkeysr
   WriteFileContentsr3   dumps)r   r+   r   sdk_def_dictcomponent_dictr9   keyr   r   r   WriteToFile  s4   
zComponentSnapshot.WriteToFilec                    sv   t  }|D ]3  | jv r8| j  jjs8| j  jjs8| j  jr8| j g|d} fdd|D }|s8|  q|S )a  Gets all the components that miss required platform-specific executables.

    Args:
      component_ids: list of str, The ids of the components to check for.
      platform_filter: platforms.Platform, A platform that components must
        match to be pulled into the dependency closure.

    Returns:
      set of str, All component ids that miss required platform-specific
        executables.
    r   c                    s$   g | ]}t |d  r|qS )z{}-)strr5   r   r   r   r   r   rC   H  s   $ zDComponentSnapshot.CheckMissingPlatformExecutable.<locals>.<listcomp>)rE   rc   r   architecturesoperating_systemsplatform_requiredr   r   )r   r   r   invalid_seedsr   	qualifiedr   r   r   CheckMissingPlatformExecutable3  s"   


z0ComponentSnapshot.CheckMissingPlatformExecutable)Frv   )r   r   r   r   recompiler(   staticmethodr/   r;   rD   r?   rk   r7   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r&   W   s:    



!$

.




3

%r&   c                   @   s   e Zd ZdZeejjejj	Z
g dZd"ddZdd Zdd	 Zd
d Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! ZdS )#r   a  Provides the ability to compare two ComponentSnapshots.

  This class is used to see how the current state-of-the-word compares to what
  we have installed.  It can be for informational purposes (to list available
  updates) but also to determine specifically what components need to be
  uninstalled / installed for a specific update command.

  Attributes:
    current: ComponentSnapshot, The current snapshot state.
    latest: CompnentSnapshot, The new snapshot that is being compared.
  )z@/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plistz(/Library/Apple/usr/share/rosetta/rosettazJ/Library/Apple/System/Library/Receipts/com.apple.pkg.RosettaUpdateAuto.bomzL/Library/Apple/System/Library/Receipts/com.apple.pkg.RosettaUpdateAuto.plistNc                    s   _ __ _ B _jr\ jjB _jj _	t
j_ jj	O  _ fddjD _j fddj	D  n fddjD _t
dd jD _t
dd jD _t
dd jD _d	S )
aB  Creates a new diff between two ComponentSnapshots.

    Args:
      current: The current ComponentSnapshot
      latest: The ComponentSnapshot representing a new state we can move to
      platform_filter: platforms.Platform, A platform that components must
        match in order to be considered for any operations.
    c                       g | ]
}t | d qS r   ComponentDiffr   r   latestr   r   r   rC         z2ComponentSnapshotDiff.__init__.<locals>.<listcomp>c                    s   g | ]}t | jd qS r   )r   DARWIN_X86_64r   )r   r   r   r   r   rC     s    c                    r   r   r   r   r   r   r   rC     r   c                 s   "    | ]}|j tju r|jV  qd S rv   )stateComponentStateREMOVEDrx   r@   diffr   r   r   rz         z1ComponentSnapshotDiff.__init__.<locals>.<genexpr>c                 s   r   rv   )r   r   NEWrx   r   r   r   r   rz     r   c                 s   r   rv   )r   r   UPDATE_AVAILABLErx   r   r   r   r   rz     s    N)r   r   '_ComponentSnapshotDiff__platform_filter_EnableFallback'_ComponentSnapshotDiff__enable_fallbackr   &_ComponentSnapshotDiff__all_componentsr   4_ComponentSnapshotDiff__all_darwin_x86_64_components0_ComponentSnapshotDiff__darwin_x86_64_componentsrE   -_ComponentSnapshotDiff__native_all_components_ComponentSnapshotDiff__diffsr   *_ComponentSnapshotDiff__removed_components&_ComponentSnapshotDiff__new_components*_ComponentSnapshotDiff__updated_components)r   r   r   r   r   )r   r   r   r   r   r   e  s:   	



zComponentSnapshotDiff.__init__c                 C   s&   | j o| j jtjjko| j jtjjkS rv   )r   operating_systemr   OperatingSystemMACOSXarchitectureArchitecturearmr"   r   r   r   r     s
   z%ComponentSnapshotDiff._EnableFallbackc                 C   s   t || j }| j|| j}|  rB| j|| j}||M }t || j }|| j@ }|rB| 	 }|sBt
dd| ||O }|rOt
dd| ||B S )zSees if any of the given components don't exist locally or remotely.

    Args:
      component_ids: list of str, The components that the user wants to update.

    Returns:
      set of str, The component ids that do not exist anywhere.
    zThe ARM versions of the components [{}] are not available yet. To download and execute the x86_64 version of the components, please install Rosetta 2 first by running the command: softwareupdate --install-rosetta., @The platform specific binary does not exist for components [{}].)rE   r   r   r   r   r   r   r   r   _CheckRosetta2Existsr   warningr   r   )r   r   r   missing_platformmissing_platform_x86_64native_invalid_idsarm_x86_idsrosetta2_installedr   r   r   InvalidUpdateSeeds  s0   	
z(ComponentSnapshotDiff.InvalidUpdateSeedsc                 C   s"   | j D ]}tj|r dS qdS )NTF)ROSETTA2_FILESr*   r+   isfile)r   r+   r   r   r   r     s
   
z*ComponentSnapshotDiff._CheckRosetta2Existsc                 C   s
   |  dS )zGets all ComponentDiffs for this snapshot comparison.

    Returns:
      The list of all ComponentDiffs between the snapshots.
    N)_FilterDiffsr"   r   r   r   AllDiffs  s   
zComponentSnapshotDiff.AllDiffsc                 C      |  tjS )z{Gets ComponentDiffs for components where there is an update available.

    Returns:
      The list of ComponentDiffs.
    )r	  r   r   r"   r   r   r   AvailableUpdates     z&ComponentSnapshotDiff.AvailableUpdatesc                 C   r  )zrGets ComponentDiffs for new components that can be installed.

    Returns:
      The list of ComponentDiffs.
    )r	  r   r   r"   r   r   r   AvailableToInstall  r  z(ComponentSnapshotDiff.AvailableToInstallc                 C   r  )zmGets ComponentDiffs for components that no longer exist.

    Returns:
      The list of ComponentDiffs.
    )r	  r   r   r"   r   r   r   Removed  r  zComponentSnapshotDiff.Removedc                 C   r  )zvGets ComponentDiffs for installed components that are up to date.

    Returns:
      The list of ComponentDiffs.
    )r	  r   
UP_TO_DATEr"   r   r   r   UpToDate  r  zComponentSnapshotDiff.UpToDatec                    s0    s| j }n
 fdd| j D }t|dd dS )Nc                    s   g | ]	}|j  u r|qS r   r   r   r  r   r   rC     s    z6ComponentSnapshotDiff._FilterDiffs.<locals>.<listcomp>c                 S      | j S rv   name)r   r   r   r   r     s    z4ComponentSnapshotDiff._FilterDiffs.<locals>.<lambda>r   )r   sorted)r   r   filteredr   r  r   r	    s   z"ComponentSnapshotDiff._FilterDiffsc                    s   t  fdd D S )z@Filter out x86_64 components that are available in arm versions.c                 3   s,    | ]}d |v r| dd v s|V  qdS )zdarwin-x86_64x86_64r   N)r6   )r@   ir   r   r   rz     s    z<ComponentSnapshotDiff.FilterDuplicatesArm.<locals>.<genexpr>r   r   r   r  r   FilterDuplicatesArm  s   z)ComponentSnapshotDiff.FilterDuplicatesArmc                 C   s,  |   rl| jj|| jd}|| jj|t|B | jdO }| jj|| jd}|| jj|t|B | jdO }||O }|| | }t| jj	 }||@ }|rXt
dd| |t| jj	 @ }| j| jB |B |@ S | jj|| jd}|| jj|t|B | jdO }|t| jj	 @ }| j| jB |@ S )a  Calculate the components that need to be uninstalled.

    Based on this given set of components, determine what we need to remove.
    When an update is done, we update all components connected to the initial
    set.  Based on this, we need to remove things that have been updated, or
    that no longer exist.  This method works with ToInstall().  For a given
    update set the update process should remove anything from ToRemove()
    followed by installing everything in ToInstall().  It is possible (and
    likely) that a component will be in both of these sets (when a new version
    is available).

    Args:
      update_seed: list of str, The component ids that we want to update.

    Returns:
      set of str, The component ids that should be removed.
    r   zfThe ARM versions of the following components are available, replacing installed x86_64 versions: [{}].r   )r   r   r   r   r   rE   r   r  rc   r   r   r   r   r   r   r   )r   update_seed	connectedconnected_darwin_x86_64x86_removal_candidatesinstalled_componentsx86_removal_seedremoval_candidatesr   r   r   ToRemove  sT   
zComponentSnapshotDiff.ToRemovec                    s  t | jj | j|| j}|  r| j|| j}| j	| }t
||@ }t
|| }||8 }||B }dd |D }|rItdd| | jj|| jd}	| jj|	t
|B | jd}
| jj|| jd}|
| jj||B | jdO }
| jj|	|B | jd}|| jj||B | jdO }|
|t
@ O }
| |
}
| j|
| j}|rtdd| |
|8 }
nD| jj|| jd}	| jj|	t
|B | jd}
| jj|	t
|B | jd}|
|t
@ O }
| j|
| j}|rtdd| |
|8 }
| j| jB  t
 fdd|
D S )	a  Calculate the components that need to be installed.

    Based on this given set of components, determine what we need to install.
    When an update is done, we update all components connected to the initial
    set.  Based on this, we need to install things that have been updated or
    that are new.  This method works with ToRemove().  For a given update set
    the update process should remove anything from ToRemove() followed by
    installing everything in ToInstall().  It is possible (and likely) that a
    component will be in both of these sets (when a new version is available).

    Args:
      update_seed: list of str, The component ids that we want to update.

    Returns:
      set of str, The component ids that should be removed.
    c                 S   s   g | ]}d |vr|qS )darwinr   r   r   r   r   rC   O  s    z3ComponentSnapshotDiff.ToInstall.<locals>.<listcomp>zhThe ARM versions of the following components are not available yet, using x86_64 versions instead: [{}].r   r   r   c                 3   s$    | ]}| v s|vr|V  qd S rv   r   ry   	differentr!  r   r   rz     s    z2ComponentSnapshotDiff.ToInstall.<locals>.<genexpr>)r   r   rc   r   r   r   r   r   r   r   rE   r   r   r   r   r   r   r  r   r   )r   r  r  missing_platform_darwin_x86_64native_valid_seednative_seeddarwin_x86_64
valid_seedplatform_seedslocal_connectedall_requiredlocal_connected_darwin_x86_64remote_connecteddep_missing_platformr   r&  r   	ToInstall1  s   




zComponentSnapshotDiff.ToInstallc                 C      t | j|dd dS )zGets the schema.Component objects for all ids from the current snapshot.

    Args:
      component_ids: list of str, The component ids to get.

    Returns:
      A list of schema.Component objects sorted by component display name.
    c                 S      | j jS rv   detailsdisplay_namer   r   r   r   r         z9ComponentSnapshotDiff.DetailsForCurrent.<locals>.<lambda>r  )r  r   r   r   r   r   r   DetailsForCurrent     	z'ComponentSnapshotDiff.DetailsForCurrentc                 C   r4  )zGets the schema.Component objects for all ids from the latest snapshot.

    Args:
      component_ids: list of str, The component ids to get.

    Returns:
      A list of schema.Component objects sorted by component display name.
    c                 S   r5  rv   r6  r   r   r   r   r     r9  z8ComponentSnapshotDiff.DetailsForLatest.<locals>.<lambda>r  )r  r   r   r   r   r   r   DetailsForLatest  r;  z&ComponentSnapshotDiff.DetailsForLatestrv   )r   r   r   r   r   Platformr   r   r   r  r   r  r   r   r  r   r
  r  r  r  r  r	  r  r$  r3  r:  r<  r   r   r   r   r   N  s*    

1"8`r   c                   @   s   e Zd ZdZdddZedd Zedd Zed	d
 Zedd Z	edd Z
edd Zedd Zedd Zedd Zdd ZdS )r   aa  Encapsulates information to be displayed for a component.

  Attributes:
    id: str, The component id.
    platform: str, The operating system and architecture of the platform.
    name: str, The display name of the component.
    current_version_string: str, The version of the component.
    is_hidden: bool, If the component is hidden.
    gdu_only: bool, If the component is only available in GDU.
    is_configuration: bool, True if this should be displayed in the packages
      section of the component manager.
    platform_required: bool, True if a platform-specific executable is
      required.
  Nc                 C   s"   || _ || _||| _|| _dS )a@  Create a new component info container.

    Args:
      component_id: str, The id of this component.
      snapshot: ComponentSnapshot, The snapshot from which to create info from.
      platform_filter: platforms.Platform, A platform that components must
        match in order to be considered for any operations.
    N)_id	_snapshotr   
_component_platform_filter)r   r   snapshotr   r   r   r   r     s   	
zComponentInfo.__init__c                 C   r  rv   )r>  r"   r   r   r   rx        zComponentInfo.idc                 C   r  rv   )rA  r"   r   r   r   r     rC  zComponentInfo.platformc                 C   
   | j jjS rv   )r@  r`   version_stringr"   r   r   r   current_version_string     
z$ComponentInfo.current_version_stringc                 C   rD  rv   )r@  r7  r8  r"   r   r   r   r    rG  zComponentInfo.namec                 C   r5  rv   )r@  r   r"   r   r   r   r        zComponentInfo.is_hiddenc                 C   r5  rv   )r@  gdu_onlyr"   r   r   r   rI    rH  zComponentInfo.gdu_onlyc                 C   r5  rv   )r@  is_configurationr"   r   r   r   rJ    rH  zComponentInfo.is_configurationc                 C   r5  rv   )r@  r   r"   r   r   r   r     rH  zComponentInfo.platform_requiredc                 C   s   | j j| j| jdS )Nr   )r?  r   r>  rA  r"   r   r   r   r     s   zComponentInfo.sizec                 C   s   dj | j| j| jdS )Nz!{name} ({id})	[{current_version}])r  rx   current_version)r   r  rx   rF  r"   r   r   r   __str__  s   zComponentInfo.__str__rv   )r   r   r   r   r   propertyrx   r   rF  r  r   rI  rJ  r   r   rL  r   r   r   r   r     s,    









r   c                   @   s,   e Zd ZdZ	d	ddZdd Zdd ZdS )
r   a  Encapsulates the difference for a single component between snapshots.

  Attributes:
    id: str, The component id.
    name: str, The display name of the component.
    current: schemas.Component, The current component definition.
    latest: schemas.Component, The latest component definition that we can move
      to.
    state: ComponentState constant, The type of difference that exists for this
      component between the given snapshots.
  Nc                 C   s   || _ ||| _||| _| jr| jjjnd| _| jr"| jjjnd| _| jr+| jn| j}|jj	| _
|j| _|j| _|j| _|j| _|  | _|| _| jrP|n|}|j||d| _dS )ai  Create a new diff.

    Args:
      component_id: str, The id of this component.
      current_snapshot: ComponentSnapshot, The base snapshot to compare against.
      latest_snapshot: ComponentSnapshot, The new snapshot.
      platform_filter: platforms.Platform, A platform that components must
        match in order to be considered for any operations.
    Nr   )rx   r   _ComponentDiff__current_ComponentDiff__latestr`   rE  rF  latest_version_stringr7  r8  r  r   rI  rJ  r   _ComputeStater   r   r   r   )r   r   current_snapshotr   r   data_provideractive_snapshotr   r   r   r     s.   

zComponentDiff.__init__c                 C   s   | j du rtjS | jdu rtjS | jjj| j jjkrtjS | jjj| j jjk rR| jjdu r6| j jdu r6tj	S t
| jjt
| j jA rEtjS | jjj| j jjkrRtjS tj	S )zReturns the component state.N)rN  r   r   rO  r   r`   build_numberr   r:   r  boolr   r"   r   r   r   rQ  "  s(   

zComponentDiff._ComputeStatec                 C   s    dj | jj| j| j| j| jdS )NzA[ {status} ]	{name} ({id})	[{current_version}]	[{latest_version}])statusr  rx   rK  latest_version)r   r   r  rx   rF  rP  r"   r   r   r   rL  =  s   zComponentDiff.__str__rv   )r   r   r   r   r   rQ  rL  r   r   r   r   r     s    
r   c                   @   sL   e Zd ZdZG dd deZedZedZedZedZ	e
dd	 Zd
S )r   z(An enum for the available update states.c                   @   s   e Zd Zdd Zdd ZdS )zComponentState._ComponentStatec                 C   s
   || _ d S rv   r  )r   r  r   r   r   r   J  s   
z'ComponentState._ComponentState.__init__c                 C   r  rv   r  r"   r   r   r   rL  M  s   z&ComponentState._ComponentState.__str__N)r   r   r   r   rL  r   r   r   r   _ComponentStateH  s    rY  	InstalledzUpdate Available
DeprecatedzNot Installedc                   C   s   t jt jt jt jgS )zbGets all the different states.

    Returns:
      list(ComponentStateTuple), All the states.
    )r   r   r   r   r  r   r   r   r   AllU  s   zComponentState.AllN)r   r   r   r   objectrY  r  r   r   r   r   r\  r   r   r   r   r   E  s    r   )r   
__future__r   r   r   r   r3   r*   r   googlecloudsdk.corer   r   r   googlecloudsdk.core.updaterr   r	   googlecloudsdk.core.utilr
   r   rO   r   r   r   r!   r$   r]  r&   r   r   r   r   r   r   r   r   <module>   s>   	   z  ^LO