@@ -6,14 +6,16 @@ use std::io::{self, Write};
6
6
use std:: path:: { Path , PathBuf } ;
7
7
use std:: str:: FromStr ;
8
8
use thiserror:: Error ;
9
+ use tracing:: warn;
9
10
10
11
use uv_state:: { StateBucket , StateStore } ;
11
12
12
13
use crate :: downloads:: Error as DownloadError ;
13
- use crate :: implementation:: Error as ImplementationError ;
14
+ use crate :: implementation:: { Error as ImplementationError , ImplementationName } ;
14
15
use crate :: platform:: Error as PlatformError ;
15
16
use crate :: platform:: { Arch , Libc , Os } ;
16
17
use crate :: python_version:: PythonVersion ;
18
+ use crate :: ToolchainRequest ;
17
19
use uv_fs:: Simplified ;
18
20
19
21
#[ derive( Error , Debug ) ]
@@ -42,8 +44,10 @@ pub enum Error {
42
44
#[ source]
43
45
err : io:: Error ,
44
46
} ,
45
- #[ error( "Failed to parse toolchain directory name: {0}" ) ]
47
+ #[ error( "Failed to read toolchain directory name: {0}" ) ]
46
48
NameError ( String ) ,
49
+ #[ error( "Failed to parse toolchain directory name `{0}`: {1}" ) ]
50
+ NameParseError ( String , String ) ,
47
51
}
48
52
/// A collection of uv-managed Python toolchains installed on the current system.
49
53
#[ derive( Debug , Clone ) ]
@@ -137,7 +141,13 @@ impl InstalledToolchains {
137
141
} ;
138
142
Ok ( dirs
139
143
. into_iter ( )
140
- . map ( |path| InstalledToolchain :: new ( path) . unwrap ( ) )
144
+ . filter_map ( |path| {
145
+ InstalledToolchain :: new ( path)
146
+ . inspect_err ( |err| {
147
+ warn ! ( "Ignoring malformed toolchain entry:\n {err}" ) ;
148
+ } )
149
+ . ok ( )
150
+ } )
141
151
. rev ( ) )
142
152
}
143
153
@@ -193,7 +203,9 @@ pub struct InstalledToolchain {
193
203
path : PathBuf ,
194
204
/// The Python version of the toolchain.
195
205
python_version : PythonVersion ,
196
- /// An install key for the toolchain
206
+ /// The name of the Python implementation of the toolchain.
207
+ implementation : ImplementationName ,
208
+ /// An install key for the toolchain.
197
209
key : String ,
198
210
}
199
211
@@ -205,14 +217,25 @@ impl InstalledToolchain {
205
217
. to_str ( )
206
218
. ok_or ( Error :: NameError ( "not a valid string" . to_string ( ) ) ) ?
207
219
. to_string ( ) ;
208
- let python_version = PythonVersion :: from_str ( key. split ( '-' ) . nth ( 1 ) . ok_or (
209
- Error :: NameError ( "not enough `-`-separated values" . to_string ( ) ) ,
220
+ let parts: Vec < & str > = key. split ( '-' ) . collect ( ) ;
221
+ let implementation = ImplementationName :: from_str ( parts. first ( ) . ok_or (
222
+ Error :: NameParseError ( key. clone ( ) , "not enough `-`-separated values" . to_string ( ) ) ,
210
223
) ?)
211
- . map_err ( |err| Error :: NameError ( format ! ( "invalid Python version: {err}" ) ) ) ?;
224
+ . map_err ( |err| {
225
+ Error :: NameParseError ( key. clone ( ) , format ! ( "invalid Python implementation: {err}" ) )
226
+ } ) ?;
227
+ let python_version = PythonVersion :: from_str ( parts. get ( 1 ) . ok_or ( Error :: NameParseError (
228
+ key. clone ( ) ,
229
+ "not enough `-`-separated values" . to_string ( ) ,
230
+ ) ) ?)
231
+ . map_err ( |err| {
232
+ Error :: NameParseError ( key. clone ( ) , format ! ( "invalid Python version: {err}" ) )
233
+ } ) ?;
212
234
213
235
Ok ( Self {
214
236
path,
215
237
python_version,
238
+ implementation,
216
239
key,
217
240
} )
218
241
}
@@ -238,6 +261,26 @@ impl InstalledToolchain {
238
261
pub fn key ( & self ) -> & str {
239
262
& self . key
240
263
}
264
+
265
+ pub fn satisfies ( & self , request : & ToolchainRequest ) -> bool {
266
+ match request {
267
+ ToolchainRequest :: File ( path) => self . executable ( ) == * path,
268
+ ToolchainRequest :: Any => true ,
269
+ ToolchainRequest :: Directory ( path) => self . path ( ) == * path,
270
+ ToolchainRequest :: ExecutableName ( name) => self
271
+ . executable ( )
272
+ . file_name ( )
273
+ . map_or ( false , |filename| filename. to_string_lossy ( ) == * name) ,
274
+ ToolchainRequest :: Implementation ( implementation) => {
275
+ * implementation == self . implementation
276
+ }
277
+ ToolchainRequest :: ImplementationVersion ( implementation, version) => {
278
+ * implementation == self . implementation
279
+ && version. matches_version ( & self . python_version )
280
+ }
281
+ ToolchainRequest :: Version ( version) => version. matches_version ( & self . python_version ) ,
282
+ }
283
+ }
241
284
}
242
285
243
286
/// Generate a platform portion of a key from the environment.
0 commit comments