
    *d/3                     ~   d Z ddlZddlZddlmZ ddlmZ ddlmZm	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mZ dd
lmZ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%  ej&        de'           Z( G d de#          Z) G d de          Z* ed           G d d                      Z+dS )a  
This module provides a convenient interface between `libmamba.Solver`
and conda's `PrefixData`. In other words, it allows to expose channels
loaded in `conda` to the `libmamba` machinery without using the
`libmamba` networking stack.

Internally, the `libmamba`'s index is made of:

- A 'Pool' object, exposed to libsolv.
- The pool is made of `Repo` objects.
- Each repo corresponds to a repodata.json file.
- Each repodata comes from a channel+subdir combination.

Some notes about channels
-------------------------

In a way, conda channels are an abstraction over a collection of
channel subdirs. For example, when the user wants 'conda-forge', it
actually means 'repodata.json' files from the configured platform subdir
and 'noarch'. Some channels are actually 'MultiChannel', which provide
a collection of channels. The most common example is 'defaults', which
includes 'main', 'r' and 'msys2'.

So, for conda-forge on Linux amd64 we get:

- https://conda.anaconda.org/conda-forge/linux-64
- https://conda.anaconda.org/conda-forge/noarch

For defaults on macOS with Apple Silicon (M1 and friends):

- https://repo.anaconda.org/main/osx-arm64
- https://repo.anaconda.org/main/noarch
- https://repo.anaconda.org/r/osx-arm64
- https://repo.anaconda.org/r/noarch
- https://repo.anaconda.org/msys2/osx-arm64
- https://repo.anaconda.org/msys2/noarch

However, users will just say 'defaults' or 'conda-forge', for convenience.
This means that we need to deal with several formats of channel information,
which ultimately lead to a collection of subdir-specific URLs:

- Channel names from the CLI or configuration files / env-vars
- Channel URLs if names are not available (channel not served in anaconda.org)
- conda.models.channel.Channel objects

Their origins can be:

- Specified by the user on the command-line (-c arguments)
- Specified by the configuration files (.condarc) or environment vars (context object)
- Added from channel-specific MatchSpec (e.g. `conda-forge::python`)
- Added from installed packages in target environment (e.g. a package that was installed
  from a non-default channel remembers where it comes from)

Also note that a channel URL might have authentication in the form:

- https://user:password@server.com/channel
- https://server.com/t/your_token_goes_here/channel

Finally, a channel can be mounted in a local directory and referred to via
a regular path, or a file:// URL, with or without normalization on Windows.

The approach
------------
We pass the subdir-specific, authenticated URLs to conda's 'SubdirData.repo_patch',
which download the JSON files but do not process them to PackageRecords.
Once the cache has been populated, we can instantiate 'libmamba.Repo' objects directly.
We maintain a map of subdir-specific URLs to `conda.model.channel.Channel`
and `libmamba.Repo` objects.
    N)	dataclass)NamedTemporaryFile)IterableUnion)REPODATA_FN)context)ThreadLimitedThreadPoolExecutor)	json_dump	json_load)remove_authsplit_anaconda_token)
SubdirData)Channel)	MatchSpec)PackageRecord   )set_channel_priorities)IndexHelper)escape_channel_urlzconda.c            	       L   e Zd Zdddefdee         deeeef                  dee         defdZ	defd	Z
	 dd
ej        dedee         dej        fdZdedej        fdZd Zdee         dej        fdZddefdZddefdZddefdZdee         dee         fdZddZdS )LibMambaIndexHelper Ninstalled_recordschannelssubdirsrepodata_fnc                     |t           j        n|| _        |t           j        n|| _        || _        g | _        t          j                    | _	        | 
                    |          }| j                            |           |                                 | _        | xj        d | j                                        D             z  c_        t          j        | j	                  | _        t          j        j        | _        d S )Nc                     g | ]	}|j         
S r   )repo).0infos     ;lib/python3.11/site-packages/conda_libmamba_solver/index.py
<listcomp>z0LibMambaIndexHelper.__init__.<locals>.<listcomp>s   s    CCCd	CCC    )r   r   	_channelsr   _subdirs_repodata_fn_reposapiPool_pool_load_installedappend_load_channels_indexvaluesQuery_queryQueryFormatJSON_format)selfr   r   r   r   installed_repos         r"   __init__zLibMambaIndexHelper.__init__a   s     .6-=))8+2?'XZZ
--.?@@>***))++CCdk.@.@.B.BCCCCi
+++r$   keyc                 
   |}|                     d          s"t          t          |                    d         }	 | j        |         S # t          $ r0}t	          d| d| dt          | j                             |d }~ww xY w)Nzfile://r   zChannel info for z (z) not found. Available keys: )
startswithr   r   r/   KeyErrorlist)r6   r9   orig_keyexcs       r"   get_infozLibMambaIndexHelper.get_infox   s    ~~i(( 	< '{3'7'788;C	;s## 	 	 	7H 7 7 7 7#'#4#47 7  	s   A 
B+A==Bpool	repo_namerecordsreturnc                    di i}i }|D ]}t          |                                          }dD ]9}||v rt          ||d          }	|	|dk    r|	rt          |	dz            }	|	||<   :||d         |j        <   t          j                    }
|j        r|j        j        |
_        |j	        r|j	        j
        r|j	        j
        |
_        |
||j        <   t          ddd	          5 }|                    t          |                     ddd           n# 1 swxY w Y   	 t          j        |||j        d
          }|                    |           |t%          j        |j                   S # t%          j        |j                   w xY w)z
        Build a libmamba 'Repo' object from conda 'PackageRecord' objects.

        This is done by rebuilding a repodata.json-like dictionary, which is
        then exported to a temporary file that will be loaded with 'libmambapy.Repo'.
        packages)sha256track_featureslicensesizeurlnoarchplatform	timestampNrN   i  z.jsonFw)suffixdeletemode )dictdumpgetattrintfnr)   ExtraPkgInforL   valuechannel
subdir_urlrepo_urlnamer   writer
   Repoadd_extra_pkg_infoosunlink)r6   rA   rB   rC   exportedadditional_infosrecordrecord_datafieldrZ   r!   fr   s                r"   _repo_from_recordsz&LibMambaIndexHelper._repo_from_records   s    # 	1 	1Fv{{}}--K	 / / K''t44$+++ #EDL 1 1).K&.9HZ + #%%D} 2$m1~ :&."; : & 9,0V[))wu3GGG 	)1GGIh''(((	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	)	8D)QVR88D##$4555IafBIafs   $#DDD2E+ +FrK   c                    t          j        |          }|j        st          d|           dt          j        v rTt          j                            || j	        f          }|r,|j
        t          d          k    rt          j        || j	        f= t          t          d          rNt                              d|           t          || j	                  }|j                                        \  }}nLt                              d|           t#          || j	                  }|                                 |j        }||fS )Nz.Channel URLs must specify a subdir! Provided: PYTEST_CURRENT_TESTinf
repo_fetchz&Fetching %s with SubdirData.repo_fetch)r   z(Fetching %s with _DownloadOnlySubdirData)r   from_urlsubdir
ValueErrorrb   environr   _cache_getr'   _mtimefloathasattrlogdebugrn   fetch_latest_path_DownloadOnlySubdirDataloadcache_path_json)r6   rK   r[   maybe_cachedsubdir_data	json_path_s          r"   _fetch_channelz"LibMambaIndexHelper._fetch_channel   s:    "3''~ 	UScSSTTT BJ.. &-1138I2JKKL A 3uU|| C C&T->'?@ :|,, 
	4II>HHH$W$:KLLLK&1CCEELIqq II@'JJJ1'tGXYYYK#3II~r$   c           	      J     fd j         D             }t          t                              |                    }t	                      5 }d |                     j        |          D             }d d d            n# 1 swxY w Y   i }|D ]~}t          j        |          }|	                    d|j
        f          d         }t          j         j        |||         t          |                    }t          ||||          ||<   t!          |           dt"          j        v r|t&                              d           g }	t*          j                                        D ]/\  }
}t1          |t2                    r|	                    |
           0|	D ]}
t*          j        |
= |S )	Nc                 l    g | ]0}t          |                              d j                  D ]}|1S )Twith_credentialsr   )r   urlsr&   )r    crK   r6   s      r"   r#   z6LibMambaIndexHelper._load_channels.<locals>.<listcomp>   sX     
 
 
qzzdmTT
 
  
 
 
 
r$   c                 4    i | ]\  }}|t          |          S r   )str)r    rK   paths      r"   
<dictcomp>z6LibMambaIndexHelper._load_channels.<locals>.<dictcomp>   s$    ___dS#d))___r$   Fr   r   )r   r[   full_url
noauth_urlrl   zCleaning up SubdirData cache)r%   tuplerT   fromkeysr	   mapr   r   ro   r   rp   r)   r`   r+   r   _ChannelRepoInfor   rb   rr   rx   ry   r   rs   items
isinstancer{   r-   )r6   r   executorjsonsindexrK   r[   r   r   clear_theser9   caches   `           r"   r.   z"LibMambaIndexHelper._load_channels   s   
 
 
 
^
 
 

 T]]4(()) -.. 	`(__x||DDWY]7^7^___E	` 	` 	` 	` 	` 	` 	` 	` 	` 	` 	` 	` 	` 	` 	`  		 		C&s++G uw~FWXXYZ[J8DJ
E#J@RS]@^@^__D 0%	! ! !E* 	u%%%
 !BJ..II4555K(06688 , ,
Ue%<== ,&&s+++" , ,&s++s   
&A<<B B c                 f    |                      | j        d|          }|                                 |S )N	installed)rj   r+   set_installed)r6   rC   r   s      r"   r,   z#LibMambaIndexHelper._load_installed  s2    &&tz;HHr$   Tqueryc                 p    | j                             || j                  }|                     ||          S N)rC   )r2   whoneedsr5   _process_query_resultr6   r   rC   
result_strs       r"   r   zLibMambaIndexHelper.whoneeds
  s4    [))%>>
))*g)FFFr$   c                 p    | j                             || j                  }|                     ||          S r   )r2   dependsr5   r   r   s       r"   r   zLibMambaIndexHelper.depends  s4    [((==
))*g)FFFr$   c                 p    | j                             || j                  }|                     ||          S r   )r2   findr5   r   r   s       r"   searchzLibMambaIndexHelper.search  s4    [%%eT\::
))*g)FFFr$   specsc                     t                      }|D ]H}|                     |                                          }|D ]}|                    |j                   It          |          S )zW
        Returns all the package names that (might) depend on the passed specs
        )setr   dist_straddr^   r   )r6   r   explicit_poolspecpkg_recordsrf   s         r"   r   z!LibMambaIndexHelper.explicit_pool  sp      	/ 	/D,,t}}77K% / /!!&+..../]###r$   c                    t          |          }|                    di                               d          dk    r|                    di                               dd          }|                    di                               dd          }|                    di                               dd|           }t          | d	| d
|           |r6g }|d         d         D ]#}t          di |}	|                    |	           $|S |S )NresultstatusOKr   typez	<Unknown>msgzFaulty response: z query 'z
' failed: pkgsr   )r   rt   rq   r   r-   )
r6   r   rC   r   
query_typer   	error_msgr   pkgrf   s
             r"   r   z)LibMambaIndexHelper._process_query_result!  s(   :&&::h##''11T99GR0044V[IIJJJw++//EEE

8R0044U<\PZ<\<\]]I
PPEPPYPPQQQ 	Kh'/ + +&----""6****r$   )r   )T)__name__
__module____qualname__r   r   r   r   r   r   r8   r@   r)   r*   r`   rj   r   r.   r,   r   r   r   r   r   r   r   r$   r"   r   r   `   s        6826!%&, ,#M2, 5#./, #	,
 , , , ,.C      RT3 3H3),37?7N3	3 3 3 3j# #(    :* * *Xx'> 38    
G Gc G G G GG GS G G G GG GC G G G G	$8I#6 	$8C= 	$ 	$ 	$ 	$     r$   r   c                   6    e Zd Zi i i dZd ZeZd Zd Zd ZdS )r{   )_package_records_names_index_track_features_indexc                     | j         S N_internal_state_templater6   argskwargss      r"   _read_local_repodataz,_DownloadOnlySubdirData._read_local_repodata8      ,,r$   c                     | j         S r   r   r   s      r"   _process_raw_repodata_strz1_DownloadOnlySubdirData._process_raw_repodata_str?  r   r$   c                     | j         S r   r   r   s      r"   _process_raw_repodataz-_DownloadOnlySubdirData._process_raw_repodataB  r   r$   c                     d S r   r   )r6   r   s     r"   
_pickle_mez"_DownloadOnlySubdirData._pickle_meE  s    r$   N)	r   r   r   r   r   _read_local_repdatar   r   r   r   r$   r"   r{   r{   1  sn        !#   - - -
 /- - -- - -    r$   r{   T)frozenc                   B    e Zd ZU eed<   ej        ed<   eed<   eed<   dS )r   r[   r   r   r   N)r   r   r   r   __annotations__r)   r`   r   r   r$   r"   r   r   I  s9         
(NNNMMMOOOOOr$   r   ),__doc__loggingrb   dataclassesr   tempfiler   typingr   r   
libmambapyr)   conda.base.constantsr   conda.base.contextr   conda.common.ior	   conda.common.serializer
   r   conda.common.urlr   r   conda.core.subdir_datar   conda.models.channelr   conda.models.match_specr   conda.models.recordsr   mamba_utilsr   stater   utilsr   	getLoggerr   rx   r   r{   r   r   r$   r"   <module>r      s  D DJ  				 ! ! ! ! ! ! ' ' ' ' ' ' " " " " " " " "     , , , , , , & & & & & & ; ; ; ; ; ; 7 7 7 7 7 7 7 7 > > > > > > > > - - - - - - ( ( ( ( ( ( - - - - - - . . . . . . / / / / / /       % % % % % %g+++,,N N N N N+ N N Nb    j   0 $         r$   